def test_athematic_rat(self): """Test RAT from single band with range values""" tmp_dir = QTemporaryDir() shutil.copy( os.path.join(os.path.dirname(__file__), 'data', '2x2_1_BAND_FLOAT.tif'), tmp_dir.path()) shutil.copy( os.path.join(os.path.dirname(__file__), 'data', '2x2_1_BAND_FLOAT.tif.aux.xml'), tmp_dir.path()) raster_layer = QgsRasterLayer( os.path.join(tmp_dir.path(), '2x2_1_BAND_FLOAT.tif'), 'rat_test', 'gdal') band = 1 rat = get_rat(raster_layer, band) self.assertTrue(rat.isValid()) self.assertEqual(rat.thematic_type, gdal.GRTT_ATHEMATIC) self.assertEqual(rat.value_columns, ['Value Min', 'Value Max']) self.assertEqual( rat.field_usages, { gdal.GFU_Generic, gdal.GFU_Name, gdal.GFU_Min, gdal.GFU_Max, gdal.GFU_Red, gdal.GFU_Green, gdal.GFU_Blue }) self.assertEqual(rat.data[rat.value_columns[0]], [-1e+25, 3000000000000.0, 1e+20]) self.assertEqual(rat.data[rat.value_columns[1]], [3000000000000.0, 1e+20, 5e+25]) # Round trip tests unique_indexes = rat_classify(raster_layer, band, rat, 'Class', ramp=None) if Qgis.QGIS_VERSION_INT >= 31800: self.assertEqual(unique_indexes, [1, 2, 3]) else: self.assertEqual(unique_indexes, [0, 1, 2]) rat2 = create_rat_from_raster( raster_layer, True, os.path.join(tmp_dir.path(), '2x2_1_BAND_FLOAT.tif.vat.dbf')) self.assertTrue(rat2.isValid()) # Generic (Class3) is gone self.assertEqual( rat2.field_usages, { gdal.GFU_Name, gdal.GFU_Min, gdal.GFU_Max, gdal.GFU_Red, gdal.GFU_Green, gdal.GFU_Blue, gdal.GFU_Alpha }) self.assertEqual(rat2.data['Value Min'], [-3.40282e+38, 3000000000000.0, 1e+20]) self.assertEqual(rat2.data['Value Max'], [3000000000000.0, 1e+20, 5e+25]) # Reclass on class 2 unique_indexes = rat_classify(raster_layer, band, rat, 'Class2', ramp=None) if Qgis.QGIS_VERSION_INT >= 31800: self.assertEqual(unique_indexes, [1, 2]) else: self.assertEqual(unique_indexes, [0, 1]) rat2 = create_rat_from_raster( raster_layer, True, os.path.join(tmp_dir.path(), '2x2_1_BAND_FLOAT.tif.vat.dbf')) self.assertTrue(rat2.isValid()) # Generic (Class3) is gone self.assertEqual( rat2.field_usages, { gdal.GFU_Name, gdal.GFU_Min, gdal.GFU_Max, gdal.GFU_Red, gdal.GFU_Green, gdal.GFU_Blue, gdal.GFU_Alpha }) self.assertEqual(rat2.data['Value Min'], [-3.40282e+38, 3000000000000.0, 1e+20]) self.assertEqual(rat2.data['Value Max'], [3000000000000.0, 1e+20, 5e+25])
def test_homogenize_colors(self): """Test color homogenize""" tmp_dir = QTemporaryDir() shutil.copy( os.path.join(os.path.dirname(__file__), 'data', 'ExistingVegetationTypes_sample.img'), tmp_dir.path()) shutil.copy( os.path.join(os.path.dirname(__file__), 'data', 'ExistingVegetationTypes_sample.img.vat.dbf'), tmp_dir.path()) raster_layer = QgsRasterLayer( os.path.join(tmp_dir.path(), 'ExistingVegetationTypes_sample.img'), 'rat_test', 'gdal') rat = get_rat(raster_layer, 1) self.assertTrue(rat.isValid()) unique_labels = rat_classify(raster_layer, 1, rat, 'EVT_NAME') if Qgis.QGIS_VERSION_INT >= 31800: self.assertEqual(unique_labels, list(range(1, 60))) else: self.assertEqual(unique_labels, list(range(0, 59))) # Get color map color_map = {} for klass in raster_layer.renderer().classes(): color_map[klass.value] = klass.color.name() # Two different colors for EVT_NAME self.assertEqual(color_map[11.0], '#0000ff') self.assertEqual(color_map[12.0], '#9fa1f0') # Reclass unique_labels = rat_classify(raster_layer, 1, rat, 'NVCSCLASS') if Qgis.QGIS_VERSION_INT >= 31800: self.assertEqual(unique_labels, [1, 3, 5, 6, 7, 22, 31, 41, 44]) else: self.assertEqual(unique_labels, [0, 2, 4, 5, 6, 21, 30, 40, 43]) color_map = {} for klass in raster_layer.renderer().classes(): color_map[klass.value] = klass.color.name() # Same colors for NVCSCLASS self.assertEqual(color_map[11.0], '#0000ff') self.assertEqual(color_map[12.0], '#0000ff') # Manually change one color classes = raster_layer.renderer().classes() classes[0].color = QColor(10, 20, 30) renderer = QgsPalettedRasterRenderer(raster_layer.dataProvider(), 1, classes) raster_layer.setRenderer(renderer) color_map = {} for klass in raster_layer.renderer().classes(): color_map[klass.value] = klass.color.name() # Manually changed colors for NVCSCLASS self.assertEqual(color_map[11.0], '#0a141e') self.assertEqual(color_map[12.0], '#0000ff') self.assertTrue(homogenize_colors(raster_layer)) color_map = {} for klass in raster_layer.renderer().classes(): color_map[klass.value] = klass.color.name() # Same colors for NVCSCLASS self.assertEqual(color_map[11.0], '#0a141e') self.assertEqual(color_map[12.0], '#0a141e')
def testStartEditingCommitRollBack(self): 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) self.assertEqual(err, QgsVectorFileWriter.NoError) self.assertTrue(os.path.isfile(newFileName)) 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) self.assertEqual(err, QgsVectorFileWriter.NoError) self.assertTrue(os.path.isfile(newFileName)) 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') self.assertTrue(layer_c.isValid()) project = QgsProject() project.addMapLayers([layer_a, layer_b, layer_c]) project.setTransactionMode(Qgis.TransactionMode.BufferedGroups) editBufferGroup = project.editBufferGroup() # Check layers in group self.assertIn(layer_a, editBufferGroup.layers()) self.assertIn(layer_b, editBufferGroup.layers()) self.assertIn(layer_c, editBufferGroup.layers()) self.assertFalse(editBufferGroup.isEditing()) self.assertTrue(editBufferGroup.startEditing()) self.assertTrue(editBufferGroup.isEditing()) self.assertTrue(layer_a.editBuffer()) self.assertTrue(layer_b.editBuffer()) self.assertTrue(layer_c.editBuffer()) self.assertEqual(len(editBufferGroup.modifiedLayers()), 0) commitErrors = [] self.assertTrue(editBufferGroup.commitChanges(commitErrors, False)) self.assertTrue(editBufferGroup.isEditing()) self.assertTrue(editBufferGroup.commitChanges(commitErrors, True)) self.assertFalse(editBufferGroup.isEditing()) self.assertTrue(editBufferGroup.startEditing()) self.assertTrue(editBufferGroup.isEditing()) f = QgsFeature(layer_a.fields()) 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()) # Check feature in layer edit buffer but not in provider till commit self.assertEqual(layer_a.featureCount(), 1) self.assertEqual(layer_a.dataProvider().featureCount(), 0) rollbackErrors = [] self.assertTrue(editBufferGroup.rollBack(rollbackErrors, False)) self.assertTrue(editBufferGroup.isEditing()) self.assertEqual(layer_a.featureCount(), 0) self.assertTrue(layer_a.addFeatures([f])) self.assertEqual(layer_a.featureCount(), 1) self.assertEqual(layer_a.dataProvider().featureCount(), 0) self.assertTrue(editBufferGroup.commitChanges(commitErrors, True)) self.assertFalse(editBufferGroup.isEditing()) self.assertEqual(layer_a.featureCount(), 1) self.assertEqual(layer_a.dataProvider().featureCount(), 1)
def _test(is_dbf): QgsProject.instance().removeAllMapLayers() tmp_dir = QTemporaryDir() shutil.copy( os.path.join(os.path.dirname(__file__), 'data', 'raster-palette.tif'), tmp_dir.path()) rat_path = os.path.join( tmp_dir.path(), 'raster-palette.tif' + ('.vat.dbf' if is_dbf else '.aux.xml')) self.assertFalse(os.path.exists(rat_path)) raster_layer = QgsRasterLayer( os.path.join(tmp_dir.path(), 'raster-palette.tif'), 'rat_test', 'gdal') QgsProject.instance().addMapLayer(raster_layer) self.assertTrue(raster_layer.isValid()) self.assertFalse(can_create_rat(raster_layer)) self.assertFalse(has_rat(raster_layer)) band = 1 # Set renderer ramp = QgsRandomColorRamp() renderer = QgsPalettedRasterRenderer( raster_layer.dataProvider(), 1, QgsPalettedRasterRenderer.classDataFromRaster( raster_layer.dataProvider(), band, ramp)) raster_layer.setRenderer(renderer) self.assertTrue(can_create_rat(raster_layer)) rat = create_rat_from_raster(raster_layer, is_dbf, rat_path) self.assertTrue(rat.isValid()) self.assertEqual(rat.data['Count'], [78, 176, 52]) self.assertEqual( rat.data['Value'], [2.257495271713565, 7.037407804695962, 270.4551067154352]) self.assertEqual(rat.data['A'], [255, 255, 255]) self.assertNotEqual(rat.data['R'], [0, 0, 0]) self.assertTrue(rat.save(band)) self.assertTrue(os.path.exists(rat_path)) QgsProject.instance().removeMapLayers([raster_layer.id()]) del (raster_layer) self.assertTrue(os.path.exists(rat_path)) QgsApplication.processEvents() # Reload and check raster_layer = QgsRasterLayer( os.path.join(tmp_dir.path(), 'raster-palette.tif'), 'rat_test', 'gdal') self.assertTrue(raster_layer.isValid()) self.assertFalse(can_create_rat(raster_layer)) self.assertTrue(has_rat(raster_layer), rat_path) os.unlink(rat_path)
def testStyles(self): """Test that styles for rasters and vectors are kept when setDataSource is called""" 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') 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] self.assertTrue(point_a_copy.isValid()) self.assertTrue(point_a.isValid()) self.assertTrue(point_b.isValid()) self.assertTrue(raster.isValid()) 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')) 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') # 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) # Now build a bad project p.removeAllMapLayers() bad_project_path = os.path.join(temp_dir.path(), 'bad_layers_test.qgs') with open(project_path, 'r') 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')) 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] 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') # 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.assertTrue(point_a.isValid()) self.assertTrue(point_a_copy.isValid()) self.assertTrue(point_b.isValid()) self.assertTrue(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(), '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)
def setUpClass(cls): """Run before all tests""" QCoreApplication.setOrganizationName("QGIS_Test") 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') # Create test DB """ Test data: Region 1 Province 1 City 1 City 2 Province 2 City 3 Region 2 Province 3 Province 4 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)) f = ogr.Feature(lyr.GetLayerDefn()) f['name'] = 'region one' lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) 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)) f = ogr.Feature(lyr.GetLayerDefn()) f['name'] = 'province one' f['region'] = 1 lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f['name'] = 'province two' f['region'] = 1 lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f['name'] = 'province three' f['region'] = 2 lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) 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)) f = ogr.Feature(lyr.GetLayerDefn()) f['name'] = 'city one' f['province'] = 1 lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f['name'] = 'city two' f['province'] = 1 lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) f['name'] = 'city three' f['province'] = 2 lyr.CreateFeature(f) f = ogr.Feature(lyr.GetLayerDefn()) 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') QgsProject.instance().addMapLayers([region, province, city]) relMgr = QgsProject.instance().relationManager() rel = QgsRelation() rel.setId('rel1') rel.setName('province -> region') rel.setReferencingLayer(province.id()) rel.setReferencedLayer(region.id()) rel.addFieldPair('region', 'fid') assert rel.isValid() relMgr.addRelation(rel) rel = QgsRelation() rel.setId('rel2') rel.setName('city -> province') rel.setReferencingLayer(city.id()) rel.setReferencedLayer(province.id()) rel.addFieldPair('province', 'fid') assert rel.isValid() relMgr.addRelation(rel)
from qdjango.apps import QGS_SERVER, get_qgs_project from qdjango.models import (ConstraintExpressionRule, ConstraintSubsetStringRule, Layer, Project, SessionTokenFilter, SessionTokenFilterLayer, SingleLayerConstraint, buildLayerTreeNodeObject) from qdjango.tests.base import CURRENT_PATH, QdjangoTestBase from qgis.core import (Qgis, QgsDataSourceUri, QgsProject, QgsProviderRegistry, QgsVectorLayer, QgsWkbTypes) from qgis.PyQt.QtCore import QTemporaryDir from qgis.PyQt.QtGui import QImage from rest_framework import status from rest_framework.test import APIClient from vcr.record_mode import RecordMode from vcr_unittest import VCRMixin temp_datasource = QTemporaryDir() @override_settings(CACHES={ 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'some', } }, LANGUAGE_CODE='en', LANGUAGES=(('en', 'English'), ), DATASOURCE_PATH=temp_datasource.path(), MEDIA_ROOT=temp_datasource.path(), HUEY={'immediate': True}) class OpenrouteserviceTest(VCRMixin, QdjangoTestBase): """Test proxy to QgsServer"""
def test_project_roundtrip(self): """Tests that a project with bad layers can be saved and restored""" p = QgsProject.instance() temp_dir = QTemporaryDir() for ext in ('shp', 'dbf', 'shx', 'prj'): copyfile(os.path.join(TEST_DATA_DIR, 'lines.%s' % ext), os.path.join(temp_dir.path(), 'lines.%s' % 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') self.assertTrue(rl.isValid()) 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') 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] self.assertTrue(vector.originalXmlProperties() != '') self.assertTrue(raster.originalXmlProperties() != '') self.assertTrue(raster_copy.originalXmlProperties() != '') # Test setter raster.setOriginalXmlProperties('pippo') self.assertEqual(raster.originalXmlProperties(), 'pippo') # Now create and invalid project: bad_project_path = os.path.join(temp_dir.path(), 'project_bad.qgs') with open(project_path, 'r') 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')) # 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] self.assertIsNotNone(vector.dataProvider()) self.assertIsNotNone(raster.dataProvider()) self.assertIsNotNone(raster_copy.dataProvider()) self.assertFalse(vector.isValid()) self.assertFalse(raster_copy.isValid()) # Try a getFeatures self.assertEqual([f for f in vector.getFeatures()], []) self.assertTrue(raster.isValid()) self.assertEqual(vector.providerType(), 'ogr') # Save the project 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') with open(bad_project_path2, 'r') 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')) # 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] self.assertTrue(vector.isValid()) self.assertTrue(raster.isValid()) self.assertTrue(raster_copy.isValid())
def testExportImport(self): p = QgsProject() manager = QgsBookmarkManager.createProjectBasedManager(p) manager2 = QgsBookmarkManager.createProjectBasedManager(p) manager3 = QgsBookmarkManager.createProjectBasedManager(p) tmpDir = QTemporaryDir() tmpFile = "{}/bookmarks.xml".format(tmpDir.path()) # no managers self.assertTrue(QgsBookmarkManager.exportToFile(tmpFile, [])) self.assertTrue(manager3.importFromFile(tmpFile)) self.assertFalse(manager3.bookmarks()) # no bookmarks self.assertTrue(QgsBookmarkManager.exportToFile(tmpFile, [manager])) self.assertTrue(manager3.importFromFile(tmpFile)) self.assertFalse(manager3.bookmarks()) # 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'))) b2 = QgsBookmark() 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'))) manager.addBookmark(b) manager.addBookmark(b2) manager2.addBookmark(b3) # 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]]) 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]]) manager3.clear() # restrict to group 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]])
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) """ 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')) project = QgsProject() self.assertTrue( project.read( os.path.join(tmp_dir.path(), 'test_project_legend.qgs'))) params = { "SERVICE": "WMS", "VERSION": "1.3", "REQUEST": "GetPrint", "TEMPLATE": "blank", "FORMAT": "png", "LAYERS": "", "map0:EXTENT": "778000,5600000,836000,5650000", "map0:SCALE": "281285", "map0:LAYERS": "red", "CRS": "EPSG:3857", "DPI": '72' } ###################################################### # Template legend tests # Legend symbol are displayed at coordinates : # First item : 600 x , 40 y # Second item : 600 x , 60 y # blank template, no theme, no LAYERS, specified map0:LAYERS is red response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the red layer is displayed, there is no second item self._assertRed(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # 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()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the green layer is displayed, there is no second item self._assertGreen(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # blank template params["map0:LAYERS"] = "" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the red layer is displayed, there is no second item self._assertRed(image.pixelColor(600, 40)) self._assertGreen(image.pixelColor(600, 60)) # red template, red theme, specified map0:LAYERS is red params["TEMPLATE"] = "red" params["map0:LAYERS"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the red layer is displayed, there is no second item self._assertRed(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # 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()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the green layer is displayed, there is no second item self._assertGreen(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # red template, red theme, no map0:LAYERS params["map0:LAYERS"] = "" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the red layer is displayed, there is no second item self._assertRed(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # green template, green theme, specified map0:LAYERS is red params["TEMPLATE"] = "green" params["map0:LAYERS"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the red layer is displayed, there is no second item self._assertRed(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # 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()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the green layer is displayed, there is no second item self._assertGreen(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # green template, green theme, no map0:LAYERS params["map0:LAYERS"] = "" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the green layer is displayed, there is no second item self._assertGreen(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # full template, full theme, specified map0:LAYERS is red params["TEMPLATE"] = "full" params["map0:LAYERS"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the red layer is displayed, there is no second item self._assertRed(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # 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()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the green layer is displayed, there is no second item self._assertGreen(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # full template, full theme, no map0:LAYERS params["map0:LAYERS"] = "" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Both red and green layers are displayed self._assertRed(image.pixelColor(600, 40)) self._assertGreen(image.pixelColor(600, 60)) # falsegreen template, falsegreen theme (green layer is blue), specified map0:LAYERS is red params["TEMPLATE"] = "falsegreen" params["map0:LAYERS"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the red layer is displayed, there is no second item self._assertRed(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # 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()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the green layer (in blue) is displayed, there is no second item self._assertBlue(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60)) # full template, full theme, no map0:LAYERS params["map0:LAYERS"] = "" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") # Only the green layer (in blue) is displayed, there is no second item self._assertBlue(image.pixelColor(600, 40)) self._assertWhite(image.pixelColor(600, 60))
from rest_framework.test import APIClient from core.models import G3WSpatialRefSys, Group as CoreGroup from core.utils.qgisapi import get_layer_fids_from_server_fids from django.core.management import call_command from qgis.PyQt.QtCore import QTemporaryDir, QDate from django.core.files import File from qdjango.models import Layer from qdjango.utils.data import QgisProject from editing.models import * from django.urls import reverse from rest_framework.test import APIClient from usersmanage.tests.utils import * # Makes a copy of test project and data into a temporary directory temp = QTemporaryDir() temp_path = temp.path() DATASOURCE_PATH = os.path.join(temp_path, 'project_data') editing_path = os.path.join( os.path.dirname(__file__), 'data', 'project_data') project_path = os.path.join(os.path.dirname(__file__), 'data', 'projects') shutil.copytree(editing_path, DATASOURCE_PATH) shutil.copytree(project_path, os.path.join( temp_path, 'projects')) QGS_DB = os.path.join(DATASOURCE_PATH, 'editing_test_transaction_group.gpkg') QGS_FILE = os.path.join(temp_path, 'projects', 'editing_test_transaction_group.qgs') QGS_DB_BACKUP = os.path.join( editing_path, 'editing_test_transaction_group.gpkg')
from django.urls import reverse from guardian.shortcuts import assign_perm, get_anonymous_user from lxml import etree as et from qdjango.apps import QGS_SERVER, get_qgs_project from qdjango.forms import QdjangoProjectForm from qdjango.models import Layer, Project from qgis.PyQt.QtCore import QTemporaryDir from .base import CURRENT_PATH, TEST_BASE_PATH, QdjangoTestBase logger = logging.getLogger(__name__) # Run the whole test in a temp MEDIA_ROOT and DATASOURCE_PATH to make sure # paths are rewritten correctly and without interferences with the existing # data TEMP_DIR = QTemporaryDir() TEMP_PATH = TEMP_DIR.path() # Directories are separate DATASOURCE_PATH = os.path.join(TEMP_PATH, 'project_data') MEDIA_ROOT = os.path.join(TEMP_PATH, 'media_root') FILE_UPLOAD_TEMP_DIR = os.path.join(TEMP_PATH, 'temp_uploads') os.mkdir(DATASOURCE_PATH) os.mkdir(MEDIA_ROOT) os.mkdir(FILE_UPLOAD_TEMP_DIR) # Copy all required data for file in glob.glob(os.path.join(CURRENT_PATH + TEST_BASE_PATH, 'geodata') + '/*.*'): shutil.copy(file, DATASOURCE_PATH) @override_settings(
def _test(autoTransaction): """Test buffer methods within and without transactions - create a feature - save - retrieve the feature - change geom and attrs - test changes are seen in the buffer """ def _check_feature(wkt): f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), wkt) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.geometry().asWkt().upper(), wkt) ml = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer', 'test', 'memory') self.assertTrue(ml.isValid()) d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'layer_a' err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'transaction_test.gpkg'), QgsCoordinateTransformContext(), options) self.assertEqual(err, QgsVectorFileWriter.NoError) self.assertTrue(os.path.isfile(os.path.join(d.path(), 'transaction_test.gpkg'))) options.layerName = 'layer_b' options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'transaction_test.gpkg'), QgsCoordinateTransformContext(), options) layer_a = QgsVectorLayer(os.path.join(d.path(), 'transaction_test.gpkg|layername=layer_a')) self.assertTrue(layer_a.isValid()) project = QgsProject() project.setAutoTransaction(autoTransaction) project.addMapLayers([layer_a]) ########################################### # Tests with a new feature self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() f = QgsFeature(layer_a.fields()) f.setAttribute('int', 123) f.setGeometry(QgsGeometry.fromWkt('point(7 45)')) self.assertTrue(layer_a.addFeatures([f])) _check_feature('POINT (7 45)') # Need to fetch the feature because its ID is NULL (-9223372036854775808) f = next(layer_a.getFeatures()) self.assertEqual(len(buffer.addedFeatures()), 1) layer_a.undoStack().undo() self.assertEqual(len(buffer.addedFeatures()), 0) layer_a.undoStack().redo() self.assertEqual(len(buffer.addedFeatures()), 1) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 123) # Now change attribute self.assertEqual(buffer.changedAttributeValues(), {}) layer_a.changeAttributeValue(f.id(), 1, 321) self.assertEqual(len(buffer.addedFeatures()), 1) # 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) layer_a.undoStack().undo() self.assertEqual(buffer.changedAttributeValues(), {}) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 123) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute('int'), 123) # Change geometry f = next(layer_a.getFeatures()) self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) _check_feature('POINT (9 43)') self.assertEqual(buffer.changedGeometries(), {}) layer_a.undoStack().undo() _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(10 44)'))) _check_feature('POINT (10 44)') # This is anothr 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)') self.assertTrue(layer_a.commitChanges()) ########################################### # Tests with the existing feature # 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.assertTrue(layer_a.startEditing()) layer_a.changeAttributeValue(f.id(), 1, 321) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {1: {1: 321}}) layer_a.undoStack().undo() self.assertEqual(buffer.changedAttributeValues(), {}) # Change geometry self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (9 43)') self.assertEqual(buffer.changedGeometries()[1].asWkt().upper(), 'POINT (9 43)') layer_a.undoStack().undo() self.assertEqual(buffer.changedGeometries(), {}) f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') self.assertEqual(buffer.changedGeometries(), {}) # Delete an existing feature self.assertTrue(layer_a.deleteFeature(f.id())) with self.assertRaises(StopIteration): next(layer_a.getFeatures()) self.assertEqual(buffer.deletedFeatureIds(), [f.id()]) layer_a.undoStack().undo() self.assertTrue(layer_a.getFeature(f.id()).isValid()) self.assertEqual(buffer.deletedFeatureIds(), []) ########################################### # Test delete # Delete a new feature f = QgsFeature(layer_a.fields()) 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] self.assertTrue(f.id() in buffer.addedFeatures()) self.assertTrue(layer_a.deleteFeature(f.id())) self.assertFalse(f.id() in buffer.addedFeatures()) self.assertFalse(f.id() in buffer.deletedFeatureIds()) layer_a.undoStack().undo() self.assertTrue(f.id() in buffer.addedFeatures()) ########################################### # Add attribute 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]) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), []) layer_a.undoStack().redo() self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), [field]) self.assertTrue(layer_a.commitChanges()) ########################################### # Remove attribute self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) self.assertTrue(layer_a.deleteAttribute(attr_idx)) self.assertEqual(buffer.deletedAttributeIds(), [2]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) layer_a.undoStack().undo() self.assertEqual(buffer.deletedAttributeIds(), []) self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) layer_a.undoStack().redo() self.assertEqual(buffer.deletedAttributeIds(), [2]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) self.assertTrue(layer_a.rollBack()) ########################################### # Rename attribute self.assertTrue(layer_a.startEditing()) attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) 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) layer_a.undoStack().redo() self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx) self.assertEqual(layer_a.fields().lookupField(field.name()), -1)
def testRelativePaths(self): """ Test whether paths to layer sources are stored as relative to the project path """ tmpDir = QTemporaryDir() tmpFile = "{}/project.qgs".format(tmpDir.path()) 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") self.assertTrue(l0.isValid()) self.assertTrue(l1.isValid()) self.assertTrue(l2.isValid()) self.assertTrue(project.addMapLayers([l0, l1, l2])) self.assertTrue(project.write(tmpFile)) del project with open(tmpFile, 'r') as f: content = ''.join(f.readlines()) self.assertTrue('source="./lines.shp"' in content) self.assertTrue('source="./points.shp"' in content) self.assertTrue('source="./landsat_4326.tif"' in content) # Re-read the project and store absolute project = QgsProject() self.assertTrue(project.read(tmpFile)) store = project.layerStore() self.assertEquals(set([l.name() for l in store.mapLayers().values()]), set(['lines', 'landsat', 'points'])) project.writeEntryBool('Paths', '/Absolute', True) tmpFile2 = "{}/project2.qgs".format(tmpDir.path()) self.assertTrue(project.write(tmpFile2)) with open(tmpFile2, 'r') as f: content = ''.join(f.readlines()) self.assertTrue( 'source="{}/lines.shp"'.format(tmpDir.path()) in content) self.assertTrue( 'source="{}/points.shp"'.format(tmpDir.path()) in content) self.assertTrue('source="{}/landsat_4326.tif"'.format( tmpDir.path()) in content) del project
def setUpTestData(cls): super().setUpTestData() cls.temp_dir = QTemporaryDir() cls.temp_project_path = os.path.join(cls.temp_dir.path(), 'pg_openrouteservice.qgs') # Create test layer conn_str = "dbname='{NAME}' host={HOST} port={PORT} user='******' password='******' sslmode=disable".format( **settings.DATABASES['default']) cls.conn_uri = conn_str md = QgsProviderRegistry.instance().providerMetadata('postgres') conn = md.createConnection(conn_str, {}) conn.executeSql( "DROP SCHEMA IF EXISTS \"openrouteservice test\" CASCADE") conn.executeSql("CREATE SCHEMA \"openrouteservice test\"") conn.executeSql( "CREATE TABLE \"openrouteservice test\".openrouteservice_poly_not_compatible ( pk SERIAL NOT NULL, name TEXT, geom GEOMETRY(POLYGON, 4326), PRIMARY KEY ( pk ) )" ) conn.executeSql( "CREATE TABLE \"openrouteservice test\".openrouteservice_point_not_compatible ( pk SERIAL NOT NULL, value NUMERIC, group_index INTEGER, area NUMERIC, reachfactor NUMERIC, total_pop INTEGER, geom GEOMETRY(POINT, 4326), PRIMARY KEY ( pk ) )" ) conn.executeSql( "CREATE TABLE \"openrouteservice test\".openrouteservice_compatible ( pk SERIAL NOT NULL, value NUMERIC, group_index INTEGER, area NUMERIC, reachfactor NUMERIC, total_pop INTEGER, geom GEOMETRY(POLYGON, 4326), PRIMARY KEY ( pk ) )" ) conn.executeSql( "CREATE TABLE \"openrouteservice test\".openrouteservice_compatible_3857 ( pk SERIAL NOT NULL, value NUMERIC, group_index INTEGER, area NUMERIC, reachfactor NUMERIC, total_pop INTEGER, geom GEOMETRY(POLYGON, 3857), PRIMARY KEY ( pk ) )" ) # Input layers for async tests conn.executeSql( "CREATE TABLE \"openrouteservice test\".openrouteservice_point_3857 ( pk SERIAL NOT NULL, geom GEOMETRY(POINT, 3857), PRIMARY KEY ( pk ) )" ) conn.executeSql( "CREATE TABLE \"openrouteservice test\".openrouteservice_multipoint_4326 ( pk SERIAL NOT NULL, geom GEOMETRY(MULTIPOINT, 4326), PRIMARY KEY ( pk ) )" ) # Add sample points for async tests conn.executeSql( """INSERT INTO "openrouteservice test".openrouteservice_multipoint_4326 (geom) VALUES ( 'SRID=4326;MULTIPOINT ((-77.55542807059459 37.56350130888833), (-77.5513628235481 37.547924590224554), (-77.53848954123421 37.58068563329007), (-77.59608054105951 37.59518182260462))'::geometry), ('SRID=4326;MULTIPOINT ((-77.4077240945721 37.538254644499624), (-77.41991983571157 37.54470141434406), (-77.4260177062813 37.55920460826607), (-77.39349572990939 37.562427156963516), (-77.40840163574651 37.58337032579007))'::geometry)""" ) conn.executeSql( """INSERT INTO "openrouteservice test".openrouteservice_point_3857 (geom) VALUES ('SRID=3857;POINT (-8636824.820306677 4510025.909782101)'::geometry), ('SRID=3857;POINT (-8633657.031688528 4512364.0394764505)'::geometry), ('SRID=3857;POINT (-8637126.514460787 4512741.157169087)'::geometry), ('SRID=3857;POINT (-8634109.572919691 4503916.603161385)'::geometry)""" ) cls.layer_specs = {} project = QgsProject() for table_name, table_spec in { 'openrouteservice_poly_not_compatible': ('Polygon', 4326), 'openrouteservice_point_not_compatible': ('Point', 4326), 'openrouteservice_compatible': ('Polygon', 4326), 'openrouteservice_compatible_3857': ('Polygon', 3857), 'openrouteservice_point_3857': ('Point', 3857), 'openrouteservice_multipoint_4326': ('MultiPoint', 4326), }.items(): layer_uri = conn_str + " sslmode=disable key='pk' estimatedmetadata=false srid={srid} type={geometry_type} checkPrimaryKeyUnicity='0' table=\"openrouteservice test\".\"{table_name}\" (geom)".format( table_name=table_name, geometry_type=table_spec[0], srid=table_spec[1]) layer = QgsVectorLayer(layer_uri, table_name, 'postgres') assert layer.isValid() cls.layer_specs[table_name] = layer_uri project.addMapLayers([layer]) assert project.write(cls.temp_project_path) Project.objects.filter(title='Test openrouteservice project').delete() toc = buildLayerTreeNodeObject(project.layerTreeRoot()) cls.qdjango_project = Project(qgis_file=File( open(cls.temp_project_path, 'r')), title='Test openrouteservice project', group=cls.project_group, layers_tree=toc) cls.qdjango_project.save() for layer_id, layer in project.mapLayers().items(): _, created = Layer.objects.get_or_create( name=layer.name(), title=layer.name(), origname=layer.name(), qgs_layer_id=layer_id, srid=layer.crs().postgisSrid(), project=cls.qdjango_project, layer_type='postgres', datasource=cls.layer_specs[layer.name()]) assert created OpenrouteserviceProject.objects.get_or_create( project=cls.qdjango_project, services={OpenrouteserviceService.ISOCHRONE.value})
def testHomePath(self): p = QgsProject() path_changed_spy = QSignalSpy(p.homePathChanged) self.assertFalse(p.homePath()) self.assertFalse(p.presetHomePath()) # simulate save file tmp_dir = QTemporaryDir() tmp_file = "{}/project.qgs".format(tmp_dir.path()) with open(tmp_file, 'w') as f: pass p.setFileName(tmp_file) # home path should be file path self.assertEqual(p.homePath(), tmp_dir.path()) self.assertFalse(p.presetHomePath()) 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') self.assertEqual(len(path_changed_spy), 2) # check project scope scope = QgsExpressionContextUtils.projectScope(p) 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') self.assertEqual(len(path_changed_spy), 2) # setting file name should not affect home path is manually set tmp_file_2 = "{}/project/project2.qgs".format(tmp_dir.path()) 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(len(path_changed_spy), 2) scope = QgsExpressionContextUtils.projectScope(p) self.assertEqual(scope.variable('project_home'), '/tmp/my_path') # clear manual path 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') # relative path 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') # relative path, no filename p.setFileName('') self.assertEqual(p.homePath(), '../home') self.assertEqual(p.presetHomePath(), '../home') scope = QgsExpressionContextUtils.projectScope(p) self.assertEqual(scope.variable('project_home'), '../home')
def test_wms_getprint_maptheme(self): """Test project has 2 layer: red and green and three templates: red: follow map theme red green: follow map theme green blank: no map theme """ tmp_dir = QTemporaryDir() shutil.copyfile( os.path.join(unitTestDataPath('qgis_server'), 'test_project_mapthemes.qgs'), os.path.join(tmp_dir.path(), 'test_project_mapthemes.qgs')) shutil.copyfile( os.path.join(unitTestDataPath('qgis_server'), 'test_project_mapthemes.gpkg'), os.path.join(tmp_dir.path(), 'test_project_mapthemes.gpkg')) project = QgsProject() self.assertTrue( project.read( os.path.join(tmp_dir.path(), 'test_project_mapthemes.qgs'))) params = { "SERVICE": "WMS", "VERSION": "1.3", "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' } polygon = 'POLYGON((7.09769689415099325 44.92867722467413216, 7.37818833364500737 44.92867722467413216, 7.37818833364500737 45.0714498943264914, 7.09769689415099325 45.0714498943264914, 7.09769689415099325 44.92867722467413216))' ###################################################### # Template map theme tests, no HIGHLIGHT # blank template, specified layer is red response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertRed(image.pixelColor(100, 100)) # blank template, specified layer is green params["map0:LAYERS"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertGreen(image.pixelColor(100, 100)) # red template, no specified layers params["map0:LAYERS"] = "" params["TEMPLATE"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertRed(image.pixelColor(100, 100)) # green template, no specified layers params["map0:LAYERS"] = "" params["TEMPLATE"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertGreen(image.pixelColor(100, 100)) # green template, specified layer is red # This is a conflict situation: the green template map is set to follow green theme # but we tell the server to render the red layer, red is what we get. params["map0:LAYERS"] = "red" params["TEMPLATE"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertRed(image.pixelColor(100, 100)) ###################################################### # Start HIGHLIGHT tests params["TEMPLATE"] = "blank" params["map0:LAYERS"] = "red" params["map0:HIGHLIGHT_GEOM"] = polygon params[ "map0:HIGHLIGHT_SYMBOL"] = r'<StyledLayerDescriptor><UserStyle><FeatureTypeStyle><Rule><PolygonSymbolizer><Fill><CssParameter name="fill">%230000FF</CssParameter></Fill></PolygonSymbolizer></Rule></FeatureTypeStyle></UserStyle></StyledLayerDescriptor>' response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertBlue(image.pixelColor(100, 100)) # Test highlight without layers params["TEMPLATE"] = "blank" params["map0:LAYERS"] = "" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertBlue(image.pixelColor(100, 100)) # Test highlight on follow theme (issue GH #34178) params["TEMPLATE"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertBlue(image.pixelColor(100, 100)) # Test highlight on follow theme (issue GH #34178) params["TEMPLATE"] = "green" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertBlue(image.pixelColor(100, 100)) # Test highlight on follow theme, but add LAYERS (issue GH #34178) params["TEMPLATE"] = "green" params["LAYERS"] = "red" response = QgsBufferServerResponse() request = QgsBufferServerRequest( '?' + '&'.join(["%s=%s" % i for i in params.items()])) self.server.handleRequest(request, response, project) image = QImage.fromData(response.body(), "PNG") self._assertBlue(image.pixelColor(100, 100))
def test_project_relations(self): """Tests that a project with bad layers and relations can be saved with relations""" temp_dir = QTemporaryDir() p = QgsProject.instance() for ext in ('qgs', 'gpkg'): copyfile(os.path.join(TEST_DATA_DIR, 'projects', 'relation_reference_test.%s' % ext), os.path.join(temp_dir.path(), 'relation_reference_test.%s' % ext)) # Load the good project 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_source = point_a.publicSource() point_b_source = point_b.publicSource() self.assertTrue(point_a.isValid()) self.assertTrue(point_b.isValid()) # Check relations def _check_relations(): relation = list(p.relationManager().relations().values())[0] self.assertTrue(relation.isValid()) self.assertEqual(relation.referencedLayer().id(), point_b.id()) self.assertEqual(relation.referencingLayer().id(), point_a.id()) _check_relations() # Now build a bad project bad_project_path = os.path.join(temp_dir.path(), 'relation_reference_test_bad.qgs') with open(project_path, 'r') 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')) # 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] self.assertFalse(point_a.isValid()) self.assertFalse(point_b.isValid()) # This fails because relations are not valid anymore with self.assertRaises(AssertionError): _check_relations() # Changing data source, relations should be restored: point_a.setDataSource(point_a_source, 'point_a', 'ogr') point_b.setDataSource(point_b_source, 'point_b', 'ogr') self.assertTrue(point_a.isValid()) self.assertTrue(point_b.isValid()) # Check if relations were restored _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] self.assertFalse(point_a.isValid()) self.assertFalse(point_b.isValid()) # This fails because relations are not valid anymore with self.assertRaises(AssertionError): _check_relations() # Save the bad project 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') with open(bad_project_path2, 'r') 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')) # 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_source = point_a.publicSource() point_b_source = point_b.publicSource() self.assertTrue(point_a.isValid()) self.assertTrue(point_b.isValid()) _check_relations()
def _test(autoTransaction): """Test buffer methods within and without transactions - create a feature - save - retrieve the feature - change geom and attrs - test changes are seen in the buffer """ def _check_feature(wkt): f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 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') 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) self.assertEqual(err, QgsVectorFileWriter.NoError) self.assertTrue(os.path.isfile(newFileName)) layer_a = QgsVectorLayer(newFileName + '|layername=layer_a') self.assertTrue(layer_a.isValid()) project = QgsProject() project.setAutoTransaction(autoTransaction) project.addMapLayers([layer_a]) ########################################### # Tests with a new feature self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() f = QgsFeature(layer_a.fields()) f.setAttribute('int', 123) f.setGeometry(QgsGeometry.fromWkt('point(7 45)')) self.assertTrue(layer_a.addFeatures([f])) _check_feature('POINT (7 45)') # Need to fetch the feature because its ID is NULL (-9223372036854775808) f = next(layer_a.getFeatures()) self.assertEqual(len(buffer.addedFeatures()), 1) layer_a.undoStack().undo() self.assertEqual(len(buffer.addedFeatures()), 0) layer_a.undoStack().redo() self.assertEqual(len(buffer.addedFeatures()), 1) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 123) # Now change attribute self.assertEqual(buffer.changedAttributeValues(), {}) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValue(f.id(), 1, 321) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321]) self.assertEqual(len(buffer.addedFeatures()), 1) # 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) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() self.assertEqual(len(spy_attribute_changed), 1) 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) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute('int'), 123) # Change multiple attributes spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValues(f.id(), {1: 321, 2: 456}) self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321]) self.assertEqual(spy_attribute_changed[1], [f.id(), 2, 456]) buffer = layer_a.editBuffer() # This is surprising: because it was a new feature it has been changed directly self.assertEqual(buffer.changedAttributeValues(), {}) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() # This is because QgsVectorLayerUndoCommandChangeAttribute plural if not autoTransaction: layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute('int'), 123) self.assertEqual(f.attribute('int2'), None) self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual( spy_attribute_changed[1 if autoTransaction else 0], [f.id(), 2, None]) self.assertEqual( spy_attribute_changed[0 if autoTransaction else 1], [f.id(), 1, 123]) # 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(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()) _check_feature('POINT (9 43)') self.assertEqual(buffer.changedGeometries(), {}) layer_a.undoStack().undo() _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(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)') self.assertTrue(layer_a.commitChanges()) ########################################### # Tests with the existing feature # 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)') # Change single attribute self.assertTrue(layer_a.startEditing()) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValue(f.id(), 1, 321) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {1: {1: 321}}) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(1), 321) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(1), 123) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 123]) self.assertEqual(buffer.changedAttributeValues(), {}) # Change attributes spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValues(f.id(), {1: 111, 2: 654}) self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual(spy_attribute_changed[0], [1, 1, 111]) self.assertEqual(spy_attribute_changed[1], [1, 2, 654]) f = next(layer_a.getFeatures()) self.assertEqual(f.attributes(), [1, 111, 654]) self.assertEqual(buffer.changedAttributeValues(), {1: { 1: 111, 2: 654 }}) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() # This is because QgsVectorLayerUndoCommandChangeAttribute plural if not autoTransaction: layer_a.undoStack().undo() self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual( spy_attribute_changed[0 if autoTransaction else 1], [1, 1, 123]) self.assertEqual( spy_attribute_changed[1 if autoTransaction else 0], [1, 2, None]) f = next(layer_a.getFeatures()) self.assertEqual(f.attributes(), [1, 123, None]) self.assertEqual(buffer.changedAttributeValues(), {}) # Change geometry spy_geometry_changed = QSignalSpy(layer_a.geometryChanged) 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()) f = next(layer_a.getFeatures()) 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(buffer.changedGeometries(), {}) f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') self.assertEqual(buffer.changedGeometries(), {}) # Delete an existing feature self.assertTrue(layer_a.deleteFeature(f.id())) with self.assertRaises(StopIteration): next(layer_a.getFeatures()) self.assertEqual(buffer.deletedFeatureIds(), [f.id()]) layer_a.undoStack().undo() self.assertTrue(layer_a.getFeature(f.id()).isValid()) self.assertEqual(buffer.deletedFeatureIds(), []) ########################################### # Test delete # Delete a new feature f = QgsFeature(layer_a.fields()) 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] self.assertTrue(f.id() in buffer.addedFeatures()) self.assertTrue(layer_a.deleteFeature(f.id())) self.assertFalse(f.id() in buffer.addedFeatures()) self.assertFalse(f.id() in buffer.deletedFeatureIds()) layer_a.undoStack().undo() self.assertTrue(f.id() in buffer.addedFeatures()) ########################################### # Add attribute 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]) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), []) layer_a.undoStack().redo() self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), [field]) self.assertTrue(layer_a.commitChanges()) ########################################### # Remove attribute self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) self.assertTrue(layer_a.deleteAttribute(attr_idx)) self.assertEqual(buffer.deletedAttributeIds(), [attr_idx]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) layer_a.undoStack().undo() self.assertEqual(buffer.deletedAttributeIds(), []) self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) # This is totally broken at least on OGR/GPKG: the rollback # does not restore the original fields if False: layer_a.undoStack().redo() self.assertEqual(buffer.deletedAttributeIds(), [attr_idx]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) # 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()) attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) self.assertTrue(layer_a.startEditing()) attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) ########################################### # 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) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) 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(field.name()), -1) ############################################# # Try hard to make this fail for transactions if autoTransaction: self.assertTrue(layer_a.commitChanges()) self.assertTrue(layer_a.startEditing()) f = next(layer_a.getFeatures()) # Do for i in range(10): spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.changeAttributeValue(f.id(), 2, i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, i]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: i }}) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), i) # Undo/redo for i in range(9): # Undo spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 8 - i) 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 }}) # Redo spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.undoStack().redo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 9 - i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, 9 - i]) # Undo again spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 8 - i) 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 }}) # Last check f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 8 - i) self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: 0 }}) layer_a.undoStack().undo() buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {}) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), None)
def test_unzip_file_empty(self): outDir = QTemporaryDir() rc, files = QgsZipUtils.unzip("", outDir.path()) self.assertFalse(rc)
def setUpTestData(cls): super().setUpTestData() project_path = os.path.join(CURRENT_PATH + TEST_BASE_PATH, 'pg_multiple_pks.qgs') cls.temp_dir = QTemporaryDir() cls.temp_project_path = os.path.join(cls.temp_dir.path(), 'pg_multiple_pks.qgs') # Create test layer conn_str = "host={HOST} port={PORT} dbname={NAME} user={USER} password={PASSWORD}".format( **settings.DATABASES['default']) md = QgsProviderRegistry.instance().providerMetadata('postgres') conn = md.createConnection(conn_str, {}) conn.executeSql("DROP TABLE IF EXISTS multiple_pks") conn.executeSql( "CREATE TABLE 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 multiple_pks VALUES ( 1, 1, '1-1', ST_GeomFromText('point(7 45)', 4326))" ) conn.executeSql( "INSERT INTO multiple_pks VALUES ( 1, 2, '1-2', ST_GeomFromText('point(8 46)', 4326))" ) cls.layer_uri = conn_str + \ " sslmode=disable key='pk1,pk2' estimatedmetadata=true srid=4326 type=Point checkPrimaryKeyUnicity='0' table=\"public\".\"multiple_pks\" (geom)" layer = QgsVectorLayer(cls.layer_uri, 'multiple_pks', 'postgres') assert layer.isValid() project = open(project_path, 'r').read() with open(cls.temp_project_path, 'w+') as f: f.write( re.sub(r'<datasource>.*</datasource>', '<datasource>%s</datasource>' % cls.layer_uri, project)) Project.objects.filter( title='Test qdjango postgres multiple_pks project').delete() cls.qdjango_project = Project( qgis_file=File(open(cls.temp_project_path, 'r')), title='Test qdjango postgres multiple_pks project', group=cls.project_group) cls.qdjango_project.save() cls.qdjango_layer, created = Layer.objects.get_or_create( name='multiple_pks', title='multiple_pks', origname='multiple_pks', qgs_layer_id='multiple_pks_67787984_68b5_423c_bc5e_ce92d8d74d70', project=cls.qdjango_project, layer_type='postgres', datasource=cls.layer_uri) assert created cls.client = APIClient()