def test_unzip_file_not_exist(self): outDir = QTemporaryDir() zip = os.path.join(self.zipDir, 'fake.zip') rc, files = QgsZipUtils.unzip(zip, outDir.path()) self.assertFalse(rc)
def testSetDataSource(self): """Test change data source""" temp_dir = QTemporaryDir() options = QgsDataProvider.ProviderOptions() myPath = os.path.join(unitTestDataPath('raster'), 'band1_float32_noct_epsg4326.tif') myFileInfo = QFileInfo(myPath) myBaseName = myFileInfo.baseName() layer = QgsRasterLayer(myPath, myBaseName) renderer = QgsSingleBandGrayRenderer(layer.dataProvider(), 2) image = layer.previewAsImage(QSize(400, 400)) self.assertFalse(image.isNull()) 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) 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) 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(filecmp.cmp(os.path.join(temp_dir.path(), 'actual.png'), os.path.join(temp_dir.path(), 'expected.png')), False)
def test_zip_unzip(self): tmpDir = QTemporaryDir() tmpFile = "{}/project.qgz".format(tmpDir.path()) project = QgsProject() l0 = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "points.shp"), "points", "ogr") l1 = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "lines.shp"), "lines", "ogr") project.addMapLayers([l0, l1]) self.assertTrue(project.write(tmpFile)) project2 = QgsProject() self.assertFalse(project2.isZipped()) self.assertTrue(project2.fileName() == "") self.assertTrue(project2.read(tmpFile)) self.assertTrue(project2.isZipped()) self.assertTrue(project2.fileName() == tmpFile) layers = project2.mapLayers() self.assertEqual(len(layers.keys()), 2) self.assertTrue(layers[l0.id()].isValid(), True) self.assertTrue(layers[l1.id()].isValid(), True) project2.clear() self.assertFalse(project2.isZipped())
def test_unzip_ok(self): outDir = QTemporaryDir() zip = os.path.join(self.zipDir, 'testzip.zip') rc, files = QgsZipUtils.unzip(zip, outDir.path()) self.assertTrue(rc) self.assertEqual(len(files), 11)
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') _, result = layer.saveNamedStyle(style_path) self.assertTrue(result) self.assertTrue(os.path.exists(style_path))
def test_zip_filename(self): tmpDir = QTemporaryDir() tmpFile = "{}/project.qgz".format(tmpDir.path()) project = QgsProject() self.assertFalse(project.write()) project.setFileName(tmpFile) self.assertTrue(project.write()) self.assertTrue(os.path.isfile(tmpFile))
def testProjectTitleWithPeriod(self): tmpDir = QTemporaryDir() tmpFile = "{}/2.18.21.qgs".format(tmpDir.path()) tmpFile2 = "{}/qgis-3.2.0.qgs".format(tmpDir.path()) p0 = QgsProject() p0.setFileName(tmpFile) p1 = QgsProject() p1.setFileName(tmpFile2) self.assertEqual(p0.baseName(), '2.18.21') self.assertEqual(p1.baseName(), 'qgis-3.2.0')
def testWriteEntry(self): tmpDir = QTemporaryDir() tmpFile = "{}/project.qgs".format(tmpDir.path()) # 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.write(tmpFile)) self.assertTrue(project.read(tmpFile)) q, ok = project.readEntry('myscope', 'myentry') self.assertTrue(ok) self.assertEqual(q, query)
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') rc = QgsZipUtils.zip(zip, [f0, f1, f2]) self.assertTrue(rc) outDir = QTemporaryDir() rc, files = QgsZipUtils.unzip(zip, outDir.path()) self.assertTrue(rc) self.assertEqual(len(files), 3)
def test_zip_new_project(self): tmpDir = QTemporaryDir() tmpFile = "{}/project.qgz".format(tmpDir.path()) # zip with existing file open(tmpFile, 'a').close() project = QgsProject() self.assertTrue(project.write(tmpFile)) # zip with non existing file os.remove(tmpFile) project = QgsProject() self.assertTrue(project.write(tmpFile)) self.assertTrue(os.path.isfile(tmpFile))
def testPalPropertiesReadWrite(self): tmpDir = QTemporaryDir() tmpFile = "{}/project.qgs".format(tmpDir.path()) s0 = QgsLabelingEngineSettings() s0.setNumCandidatePositions(3, 33, 333) p0 = QgsProject() p0.setFileName(tmpFile) p0.setLabelingEngineSettings(s0) p0.write() p1 = QgsProject() p1.read(tmpFile) s1 = p1.labelingEngineSettings() candidates = s1.numCandidatePositions() self.assertEqual(candidates[0], 3) self.assertEqual(candidates[1], 33) self.assertEqual(candidates[2], 333)
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))
class TestRATModel(TestCase): @classmethod def setUpClass(cls): cls.qgs = QgsApplication([], False) cls.qgs.initQgis() def setUp(self): self.tmp_dir = QTemporaryDir() self.tmp_path = os.path.join(self.tmp_dir.path(), 'data') shutil.copytree(os.path.join(os.path.dirname(__file__), 'data'), self.tmp_path) self.raster_layer = QgsRasterLayer( os.path.join( self.tmp_path, 'NBS_US5PSMBE_20200923_0_generalized_p.source_information.tiff' ), 'rat_test', 'gdal') self.assertTrue(self.raster_layer.isValid()) self.raster_layer_color = QgsRasterLayer( os.path.join(self.tmp_path, 'ExistingVegetationTypes_sample.img'), 'rat_test', 'gdal') self.assertTrue(self.raster_layer_color.isValid()) def test_insert_column(self): rat = get_rat(self.raster_layer, 1) self.assertTrue(rat.isValid()) model = RATModel(rat) tester = QAbstractItemModelTester( model, QAbstractItemModelTester.FailureReportingMode.Warning) column_count = model.columnCount(QModelIndex()) field = RATField('f1', gdal.GFU_Generic, gdal.GFT_String) self.assertTrue(model.insert_column(3, field)[0]) self.assertEqual(model.columnCount(QModelIndex()), column_count + 1) self.assertEqual(model.headers.index('f1'), 3) # Error field = RATField('f1', gdal.GFU_Generic, gdal.GFT_String) self.assertFalse(model.insert_column(3, field)[0]) self.assertEqual(model.columnCount(QModelIndex()), column_count + 1) def test_insert_column_color(self): rat = get_rat(self.raster_layer_color, 1) self.assertTrue(rat.isValid()) model = RATModel(rat) tester = QAbstractItemModelTester( model, QAbstractItemModelTester.FailureReportingMode.Warning) column_count = model.columnCount(QModelIndex()) field = RATField('f1', gdal.GFU_Generic, gdal.GFT_String) self.assertTrue(model.insert_column(3, field)[0]) self.assertEqual(model.columnCount(QModelIndex()), column_count + 1) self.assertEqual(model.headers.index('f1'), 3) # Error field = RATField('f1', gdal.GFU_Generic, gdal.GFT_String) self.assertFalse(model.insert_column(3, field)[0]) self.assertEqual(model.columnCount(QModelIndex()), column_count + 1) def test_remove_column(self): rat = get_rat(self.raster_layer, 1) self.assertTrue(rat.isValid()) model = RATModel(rat) tester = QAbstractItemModelTester( model, QAbstractItemModelTester.FailureReportingMode.Warning) column_count = model.columnCount(QModelIndex()) self.assertFalse(model.remove_column(0)[0]) self.assertFalse(model.remove_column(1)[0]) self.assertTrue(model.remove_column(2)[0]) self.assertEqual(model.columnCount(QModelIndex()), column_count - 1) def test_edit_color(self): rat = get_rat(self.raster_layer_color, 1) model = RATModel(rat) tester = QAbstractItemModelTester( model, QAbstractItemModelTester.FailureReportingMode.Warning) index = model.index(0, 0) value = QColor(Qt.magenta) model.setData(index, value) self.assertEqual(model.data(index, Qt.BackgroundColorRole), value) def test_remove_color(self): rat = get_rat(self.raster_layer_color, 1) model = RATModel(rat) tester = QAbstractItemModelTester( model, QAbstractItemModelTester.FailureReportingMode.Warning) self.assertTrue({'R', 'G', 'B'}.issubset(rat.keys)) self.assertTrue({'R', 'G', 'B'}.issubset(model.headers)) self.assertTrue(model.has_color) column_count = model.columnCount(QModelIndex()) self.assertEqual(column_count, 17) # Remove colors self.assertTrue(model.remove_color()) self.assertEqual(model.columnCount(QModelIndex()), column_count - 4) self.assertFalse(rat.has_color) self.assertFalse(model.has_color) self.assertFalse({'R', 'G', 'B'}.issubset(rat.keys)) self.assertFalse({'R', 'G', 'B'}.issubset(model.headers)) # Add color back (with alpha) self.assertTrue(model.insert_color(2)) self.assertEqual(model.columnCount(QModelIndex()), column_count + 1) self.assertTrue({'R', 'G', 'B'}.issubset(rat.keys)) self.assertTrue({'R', 'G', 'B'}.issubset(model.headers)) self.assertTrue(rat.has_color) self.assertTrue(model.has_color) self.assertTrue(RAT_COLOR_HEADER_NAME in rat.keys) def test_add_remove_row(self): def _test(raster_layer): rat = get_rat(self.raster_layer_color, 1) model = RATModel(rat) tester = QAbstractItemModelTester( model, QAbstractItemModelTester.FailureReportingMode.Warning) row_count = model.rowCount(QModelIndex()) value_index = 1 if model.has_color else 0 value_0 = model.data(model.index(0, value_index, QModelIndex())) value_last = model.data( model.index(row_count - 1, value_index, QModelIndex())) # Insert first self.assertTrue(model.insert_row(0)) self.assertEqual(model.rowCount(QModelIndex()), row_count + 1) self.assertNotEqual( model.data(model.index(0, value_index, QModelIndex())), value_0) self.assertEqual( model.data(model.index(0, value_index, QModelIndex())), 0) self.assertTrue(model.remove_row(0)) self.assertEqual(model.rowCount(QModelIndex()), row_count) self.assertEqual( model.data(model.index(0, value_index, QModelIndex())), value_0) # Insert last self.assertTrue(model.insert_row(row_count)) self.assertEqual(model.rowCount(QModelIndex()), row_count + 1) self.assertNotEqual( model.data(model.index(row_count, value_index, QModelIndex())), value_last) self.assertEqual( model.data(model.index(row_count, value_index, QModelIndex())), 0) self.assertEqual( model.data( model.index(row_count - 1, value_index, QModelIndex())), value_last) self.assertTrue(model.remove_row(row_count)) self.assertEqual(model.rowCount(QModelIndex()), row_count) self.assertEqual( model.data( model.index(row_count - 1, value_index, QModelIndex())), value_last) _test(self.raster_layer) _test(self.raster_layer_color) def test_header_tooltip(self): rat = get_rat(self.raster_layer_color, 1) model = RATModel(rat) tooltip = model.getHeaderTooltip(1) self.assertIn('<dt>Role</dt><dd>Class value(min=max)</dd>', tooltip) self.assertIn('<dt>Type</dt><dd>Integer</dd>', tooltip) tooltip = model.getHeaderTooltip(2) self.assertIn('<dt>Role</dt><dd>Histogram pixel count</dd>', tooltip) self.assertIn('<dt>Type</dt><dd>Integer</dd>', tooltip) tooltip = model.getHeaderTooltip(3) self.assertIn('<dt>Role</dt><dd>General purpose field</dd>', tooltip) self.assertIn('<dt>Type</dt><dd>String</dd>', tooltip)
class TestRATClasses(TestCase): @classmethod def setUpClass(cls): cls.qgs = QgsApplication([], False) cls.qgs.initQgis() @classmethod def tearDownClass(cls): cls.qgs.exitQgis() def tearDown(self): del (self.raster_layer) del (self.raster_layer_dbf) del (self.raster_layer_athematic) def setUp(self): self.tmp_dir = QTemporaryDir() self.tmp_path = os.path.join(self.tmp_dir.path(), 'data') shutil.copytree(os.path.join(os.path.dirname(__file__), 'data'), self.tmp_path) self.raster_layer = QgsRasterLayer( os.path.join( self.tmp_path, 'NBS_US5PSMBE_20200923_0_generalized_p.source_information.tiff' ), 'rat_test', 'gdal') self.assertTrue(self.raster_layer.isValid()) self.raster_layer_dbf = QgsRasterLayer( os.path.join(self.tmp_path, 'ExistingVegetationTypes_sample.img'), 'rat_test', 'gdal') self.assertTrue(self.raster_layer_dbf.isValid()) self.raster_layer_athematic = QgsRasterLayer( os.path.join(self.tmp_path, '2x2_1_BAND_FLOAT.tif'), 'rat_test', 'gdal') self.assertTrue(self.raster_layer_athematic.isValid()) def test_field_usages(self): rat = get_rat(self.raster_layer, 1) self.assertTrue(rat.isValid()) self.assertEqual(rat.field_usages, {0, 1, 5}) def test_insert_column(self): rat = get_rat(self.raster_layer, 1) self.assertTrue(rat.isValid()) self.assertEqual(len(rat.keys), 16) self.assertEqual(len(rat.keys), len(rat.fields)) # Not valid insertions field = RATField('f1', gdal.GFU_MinMax, gdal.GFT_Real) self.assertFalse(rat.insert_column(4, field)[0]) field = RATField('f1', gdal.GFU_Generic, gdal.GFT_Real) self.assertFalse(rat.insert_column(0, field)[0]) field = RATField('f1', gdal.GFU_Generic, gdal.GFT_Real) self.assertFalse(rat.insert_column(1, field)[0]) field = RATField('f1', gdal.GFU_Generic, gdal.GFT_Real) self.assertFalse(rat.insert_column(100, field)[0]) field = RATField('significant_features', gdal.GFU_Generic, gdal.GFT_Real) self.assertFalse(rat.insert_column(4, field)[0]) # Valid insertions field = RATField('f1', gdal.GFU_Generic, gdal.GFT_Real) self.assertEqual(field.qgis_type, QVariant.Double) self.assertTrue(rat.insert_column(4, field)[0]) self.assertIn('f1', rat.fields.keys()) self.assertEqual(len(rat.data['f1']), len(rat.data['Value'])) field = RATField('f2', gdal.GFU_Generic, gdal.GFT_Integer) self.assertEqual(field.qgis_type, QVariant.Int) self.assertTrue(rat.insert_column(2, field)[0]) self.assertIn('f2', rat.fields.keys()) self.assertEqual(len(rat.data['f2']), len(rat.data['Value'])) self.assertEqual(rat.data['f2'][0], 0) field = RATField('f3', gdal.GFU_Generic, gdal.GFT_String) self.assertEqual(field.qgis_type, QVariant.String) self.assertTrue(rat.insert_column(len(rat.keys) - 1, field)[0]) self.assertIn('f3', rat.fields.keys()) self.assertEqual(len(rat.data['f3']), len(rat.data['Value'])) self.assertEqual(rat.data['f3'][0], '') def test_remove_column(self): rat = get_rat(self.raster_layer, 1) self.assertTrue(rat.isValid()) self.assertEqual(len(rat.keys), 16) self.assertEqual(len(rat.keys), len(rat.fields)) # Invalid removals self.assertFalse(rat.remove_column('Value')[0]) self.assertFalse(rat.remove_column('Count')[0]) self.assertFalse(rat.remove_column('not found')[0]) # Valid removals self.assertTrue(rat.remove_column('data_assessment')[0]) self.assertEqual(len(rat.keys), 15) self.assertEqual(len(rat.keys), len(rat.fields)) def test_insert_column_dbf(self): rat = get_rat(self.raster_layer_dbf, 1) self.assertTrue(rat.isValid()) self.assertEqual(len(rat.keys), 17) # has color, so fields are one more than keys self.assertEqual(len(rat.keys), len(rat.fields) + 1) # Not valid insertions field = RATField('f1', gdal.GFU_MinMax, gdal.GFT_Real) self.assertFalse(rat.insert_column(4, field)[0]) field = RATField('f1', gdal.GFU_Generic, gdal.GFT_Real) self.assertFalse(rat.insert_column(0, field)[0]) field = RATField('f1', gdal.GFU_Generic, gdal.GFT_Real) self.assertFalse(rat.insert_column(1, field)[0]) field = RATField('f1', gdal.GFU_Generic, gdal.GFT_Real) self.assertFalse(rat.insert_column(100, field)[0]) field = RATField('SYSTMGRPNA', gdal.GFU_Generic, gdal.GFT_Real) self.assertFalse(rat.insert_column(4, field)[0]) # Valid insertions field = RATField('f1', gdal.GFU_Generic, gdal.GFT_Real) self.assertEqual(field.qgis_type, QVariant.Double) self.assertTrue(rat.insert_column(4, field)[0]) self.assertIn('f1', rat.fields.keys()) self.assertEqual(len(rat.data['f1']), len(rat.data['VALUE'])) field = RATField('f2', gdal.GFU_Generic, gdal.GFT_Integer) self.assertEqual(field.qgis_type, QVariant.Int) self.assertTrue(rat.insert_column(2, field)[0]) self.assertIn('f2', rat.fields.keys()) self.assertEqual(len(rat.data['f2']), len(rat.data['VALUE'])) self.assertEqual(rat.data['f2'][0], 0) field = RATField('f3', gdal.GFU_Generic, gdal.GFT_String) self.assertEqual(field.qgis_type, QVariant.String) self.assertTrue(rat.insert_column(len(rat.keys) - 1, field)[0]) self.assertIn('f3', rat.fields.keys()) self.assertEqual(len(rat.data['f3']), len(rat.data['VALUE'])) self.assertEqual(rat.data['f3'][0], '') field = RATField('R', gdal.GFU_Red, gdal.GFT_Integer) self.assertFalse(rat.insert_column(len(rat.keys) - 1, field)[0]) def test_remove_column_dbf(self): rat = get_rat(self.raster_layer_dbf, 1) self.assertTrue(rat.isValid()) self.assertEqual(len(rat.keys), 17) self.assertEqual(len(rat.keys), len(rat.fields) + 1) # Invalid removals self.assertFalse(rat.remove_column('VALUE')[0]) self.assertFalse(rat.remove_column('COUNT')[0]) self.assertFalse(rat.remove_column('not found')[0]) # Valid removals self.assertTrue(rat.remove_column('SYSTMGRPNA')[0]) self.assertEqual(len(rat.keys), 16) self.assertEqual(len(rat.keys), len(rat.fields) + 1) def test_qgis_features(self): rat = get_rat(self.raster_layer_dbf, 1) features = rat.qgis_features() self.assertEqual(len(features), 59) rat = get_rat(self.raster_layer, 1) features = rat.qgis_features() self.assertEqual(len(features), 27) def test_get_set_color(self): rat = get_rat(self.raster_layer_dbf, 1) color = rat.get_color(0) self.assertTrue(color.isValid()) # Invalid self.assertFalse(rat.get_color(-1).isValid()) self.assertFalse(rat.get_color(100).isValid()) # Setter self.assertTrue(rat.set_color(1, QColor(10, 20, 30, 120))) self.assertEqual(rat.get_color(1), QColor(10, 20, 30, 120)) def test_field_name(self): rat = get_rat(self.raster_layer_dbf, 1) usages = [] for field in rat.fields.values(): if field.usage not in usages: usages.append(field.usage) self.assertEqual(rat.field_name(field.usage), field.name) self.assertEqual(rat.field_name(gdal.GFU_AlphaMax), '') self.assertEqual(rat.field_name(gdal.GFU_RedMax), '') self.assertEqual(rat.field_name(gdal.GFU_RedMin), '') def test_update_color_from_raster(self): rat = get_rat(self.raster_layer_dbf, 1) self.assertTrue(rat.has_color) rat_classify(self.raster_layer_dbf, 1, rat, 'EVT_NAME') color_map = { klass.value: klass.color for klass in self.raster_layer_dbf.renderer().classes() } # Remove color self.assertTrue(rat.remove_color_fields()) self.assertFalse(rat.has_color) # Add color result, error_message = rat.insert_color_fields(len(rat.keys) - 1) self.assertTrue(result, error_message) self.assertTrue(rat.has_color) for color in rat.data[RAT_COLOR_HEADER_NAME]: self.assertEqual(color, QColor(Qt.black)) # Update color from raster self.assertTrue(rat.update_colors_from_raster(self.raster_layer_dbf)) value_column = rat.value_columns[0] self.assertEqual(value_column, rat.field_name(gdal.GFU_MinMax)) for row_index in range(len(rat.data[RAT_COLOR_HEADER_NAME])): self.assertEqual(rat.data[RAT_COLOR_HEADER_NAME][row_index], color_map[rat.data[value_column][row_index]]) def test_update_color_from_raster_athematic(self): rat = get_rat(self.raster_layer_athematic, 1) self.assertTrue(rat.has_color) rat_classify(self.raster_layer_athematic, 1, rat, 'Class') shader = self.raster_layer_athematic.renderer().shader() colorRampShaderFcn = shader.rasterShaderFunction() classes = classes = colorRampShaderFcn.colorRampItemList() color_map = {klass.value: klass.color for klass in classes} # Remove color self.assertTrue(rat.remove_color_fields()) self.assertFalse(rat.has_color) # Add color result, error_message = rat.insert_color_fields(len(rat.keys) - 1) self.assertTrue(result, error_message) self.assertTrue(rat.has_color) for color in rat.data[RAT_COLOR_HEADER_NAME]: self.assertEqual(color, QColor(Qt.black)) # Update color from raster self.assertTrue( rat.update_colors_from_raster(self.raster_layer_athematic)) value_column = rat.value_columns[1] self.assertEqual(value_column, rat.field_name(gdal.GFU_Max)) for row_index in range(len(rat.data[RAT_COLOR_HEADER_NAME])): self.assertEqual(rat.data[RAT_COLOR_HEADER_NAME][row_index], color_map[rat.data[value_column][row_index]]) def test_add_remove_row(self): def _test(raster_layer): rat = get_rat(raster_layer, 1) value_column = rat.value_columns[0] self.assertEqual(value_column, rat.field_name(gdal.GFU_MinMax)) self.assertNotEqual(rat.data[value_column][-1], 0) row_count = len(rat.data[value_column]) result, error_message = rat.insert_row(0) self.assertTrue(result) self.assertEqual(len(rat.data[value_column]), row_count + 1) self.assertEqual(rat.data[value_column][0], 0) result, error_message = rat.remove_row(0) self.assertTrue(result) self.assertEqual(len(rat.data[value_column]), row_count) self.assertNotEqual(rat.data[value_column][0], 0) last = len(rat.data[value_column]) result, error_message = rat.insert_row(last) self.assertTrue(result) self.assertEqual(len(rat.data[value_column]), row_count + 1) self.assertEqual(rat.data[value_column][last], 0) result, error_message = rat.remove_row(last) self.assertTrue(result) self.assertEqual(len(rat.data[value_column]), row_count) self.assertNotEqual(rat.data[value_column][last - 1], 0) # Invalid ranges last = len(rat.data[value_column]) self.assertFalse(rat.insert_row(-1)[0]) self.assertFalse(rat.insert_row(last + 1)[0]) self.assertFalse(rat.remove_row(-1)[0]) self.assertFalse(rat.remove_row(last)[0]) _test(self.raster_layer_dbf) _test(self.raster_layer) def test_edit_rat(self): raster_layer = QgsRasterLayer( os.path.join(self.tmp_path, '2x2_2_BANDS_INT16.tif'), 'rat_test', 'gdal') self.assertTrue(raster_layer.isValid()) band = 1 rat = get_rat(raster_layer, band) self.assertTrue(rat.isValid()) self.assertEqual(rat.data['Red'], [0, 100, 200]) rat.data['Red'] = [111, 222, 123] rat.save(band) rat = get_rat(raster_layer, band) self.assertTrue(rat.isValid()) self.assertEqual(rat.data['Red'], [111, 222, 123]) def test_athematic_dbf_roundtrip(self): """Test that saving as athematic and reloading does not loose type""" rat = get_rat(self.raster_layer_athematic, 1) self.assertTrue(rat.has_color) self.assertTrue(rat.isValid()) self.assertEqual(rat.thematic_type, gdal.GRTT_ATHEMATIC) # Delete the layer and the PAM file raster_source = self.raster_layer_athematic.source() pam_path = raster_source + '.aux.xml' del (self.raster_layer_athematic) os.unlink(pam_path) rat.save_as_dbf(raster_source) self.assertTrue(os.path.exists(raster_source + '.vat.dbf')) self.raster_layer_athematic = QgsRasterLayer(raster_source, 'rat_test', 'gdal') rat_dbf = get_rat(self.raster_layer_athematic, 1) self.assertTrue(rat_dbf.has_color) self.assertTrue(rat_dbf.isValid()) self.assertEqual(rat_dbf.thematic_type, gdal.GRTT_ATHEMATIC) self.assertEqual( rat_dbf.field_usages, { gdal.GFU_Generic, gdal.GFU_Red, gdal.GFU_Green, gdal.GFU_Blue, gdal.GFU_Min, gdal.GFU_Max, }) def test_charset(self): """Test that we can save/load non-ASCII chars""" rat = get_rat(self.raster_layer, 1) self.assertTrue(rat.isValid()) # Delete the layer and the PAM file raster_source = self.raster_layer.source() pam_path = raster_source + '.aux.xml' dbf_path = raster_source + '.vat.dbf' del (self.raster_layer) os.unlink(pam_path) rat.data['License_Name'][0] = 'Some accented chars èé 😁' rat.save_as_dbf(raster_source) self.assertTrue(os.path.exists(dbf_path)) self.raster_layer = QgsRasterLayer(raster_source, 'rat_test', 'gdal') rat_dbf = get_rat(self.raster_layer, 1) self.assertTrue(rat_dbf.isValid()) self.assertEqual(rat_dbf.data['License_Na'][0], 'Some accented chars èé 😁') # Save as XML rat.save_as_xml(raster_source, 1) self.assertTrue(os.path.exists(pam_path)) del (self.raster_layer) os.unlink(dbf_path) self.raster_layer = QgsRasterLayer(raster_source, 'rat_test', 'gdal') rat_xml = get_rat(self.raster_layer, 1) self.assertTrue(rat_xml.isValid()) self.assertEqual(rat_xml.data['License_Name'][0], 'Some accented chars èé 😁')
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)
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 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_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 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
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_unzip_file_empty(self): outDir = QTemporaryDir() rc, files = QgsZipUtils.unzip("", outDir.path()) self.assertFalse(rc)
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(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 testSymbolicLinkInProjectPath(self): """ Test whether paths to layer sources relative to the project are stored correctly when project'name contains a symbolic link. In other words, test if project's and layers' names are correctly resolved. """ 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 # Create symbolic link to previous project tmpDir2 = QTemporaryDir() symlinkDir = os.path.join(tmpDir2.path(), "dir") os.symlink(tmpDir.path(), symlinkDir) tmpFile = "{}/project.qgs".format(symlinkDir) # Open project from symmlink and force re-save. project = QgsProject() self.assertTrue(project.read(tmpFile)) 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)
def testStyles(self): """Test that styles for rasters and vectors are kept when setDataSource is called""" options = QgsDataProvider.ProviderOptions() 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() self.assertTrue(p.read(project_path)) self.assertEqual(p.count(), 3) ms = self.getBaseMapSettings() 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.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, point_b, raster]) image = renderMapToImage(ms) print(os.path.join(temp_dir.path(), 'expected.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() point_a.setDataSource(point_a_source, point_a.name(), 'ogr', options) point_b.setDataSource(point_b_source, point_b.name(), 'ogr', options) raster.setDataSource(raster_source, raster.name(), 'gdal', options) 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 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')) self.assertTrue(p.read(bad_project_path)) self.assertEqual(p.count(), 3) 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_b.isValid()) self.assertFalse(raster.isValid()) point_a.setDataSource(point_a_source, point_a.name(), 'ogr', options) point_b.setDataSource(point_b_source, point_b.name(), 'ogr', options) raster.setDataSource(raster_source, raster.name(), 'gdal', options) 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 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 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})
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
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')
def testSymbolicLinkInProjectPath(self): """ Test whether paths to layer sources relative to the project are stored correctly when project'name contains a symbolic link. In other words, test if project's and layers' names are correctly resolved. """ 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 # Create symbolic link to previous project tmpDir2 = QTemporaryDir() symlinkDir = os.path.join(tmpDir2.path(), "dir") os.symlink(tmpDir.path(), symlinkDir) tmpFile = "{}/project.qgs".format(symlinkDir) # Open project from symmlink and force re-save. project = QgsProject() self.assertTrue(project.read(tmpFile)) 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)
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_unzip_file_empty(self): outDir = QTemporaryDir() rc, files = QgsZipUtils.unzip("", outDir.path()) self.assertFalse(rc)
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 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') 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 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 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 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_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_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 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 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 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 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()