Beispiel #1
0
    def test_athematic_rat(self):
        """Test RAT from single band with range values"""

        tmp_dir = QTemporaryDir()

        shutil.copy(
            os.path.join(os.path.dirname(__file__), 'data',
                         '2x2_1_BAND_FLOAT.tif'), tmp_dir.path())

        shutil.copy(
            os.path.join(os.path.dirname(__file__), 'data',
                         '2x2_1_BAND_FLOAT.tif.aux.xml'), tmp_dir.path())

        raster_layer = QgsRasterLayer(
            os.path.join(tmp_dir.path(), '2x2_1_BAND_FLOAT.tif'), 'rat_test',
            'gdal')

        band = 1

        rat = get_rat(raster_layer, band)
        self.assertTrue(rat.isValid())
        self.assertEqual(rat.thematic_type, gdal.GRTT_ATHEMATIC)
        self.assertEqual(rat.value_columns, ['Value Min', 'Value Max'])
        self.assertEqual(
            rat.field_usages, {
                gdal.GFU_Generic, gdal.GFU_Name, gdal.GFU_Min, gdal.GFU_Max,
                gdal.GFU_Red, gdal.GFU_Green, gdal.GFU_Blue
            })
        self.assertEqual(rat.data[rat.value_columns[0]],
                         [-1e+25, 3000000000000.0, 1e+20])
        self.assertEqual(rat.data[rat.value_columns[1]],
                         [3000000000000.0, 1e+20, 5e+25])

        # Round trip tests
        unique_indexes = rat_classify(raster_layer,
                                      band,
                                      rat,
                                      'Class',
                                      ramp=None)

        if Qgis.QGIS_VERSION_INT >= 31800:
            self.assertEqual(unique_indexes, [1, 2, 3])
        else:
            self.assertEqual(unique_indexes, [0, 1, 2])

        rat2 = create_rat_from_raster(
            raster_layer, True,
            os.path.join(tmp_dir.path(), '2x2_1_BAND_FLOAT.tif.vat.dbf'))
        self.assertTrue(rat2.isValid())
        # Generic (Class3) is gone
        self.assertEqual(
            rat2.field_usages, {
                gdal.GFU_Name, gdal.GFU_Min, gdal.GFU_Max, gdal.GFU_Red,
                gdal.GFU_Green, gdal.GFU_Blue, gdal.GFU_Alpha
            })
        self.assertEqual(rat2.data['Value Min'],
                         [-3.40282e+38, 3000000000000.0, 1e+20])
        self.assertEqual(rat2.data['Value Max'],
                         [3000000000000.0, 1e+20, 5e+25])

        # Reclass on class 2
        unique_indexes = rat_classify(raster_layer,
                                      band,
                                      rat,
                                      'Class2',
                                      ramp=None)

        if Qgis.QGIS_VERSION_INT >= 31800:
            self.assertEqual(unique_indexes, [1, 2])
        else:
            self.assertEqual(unique_indexes, [0, 1])

        rat2 = create_rat_from_raster(
            raster_layer, True,
            os.path.join(tmp_dir.path(), '2x2_1_BAND_FLOAT.tif.vat.dbf'))
        self.assertTrue(rat2.isValid())
        # Generic (Class3) is gone
        self.assertEqual(
            rat2.field_usages, {
                gdal.GFU_Name, gdal.GFU_Min, gdal.GFU_Max, gdal.GFU_Red,
                gdal.GFU_Green, gdal.GFU_Blue, gdal.GFU_Alpha
            })
        self.assertEqual(rat2.data['Value Min'],
                         [-3.40282e+38, 3000000000000.0, 1e+20])
        self.assertEqual(rat2.data['Value Max'],
                         [3000000000000.0, 1e+20, 5e+25])
Beispiel #2
0
    def test_homogenize_colors(self):
        """Test color homogenize"""

        tmp_dir = QTemporaryDir()
        shutil.copy(
            os.path.join(os.path.dirname(__file__), 'data',
                         'ExistingVegetationTypes_sample.img'), tmp_dir.path())
        shutil.copy(
            os.path.join(os.path.dirname(__file__), 'data',
                         'ExistingVegetationTypes_sample.img.vat.dbf'),
            tmp_dir.path())

        raster_layer = QgsRasterLayer(
            os.path.join(tmp_dir.path(), 'ExistingVegetationTypes_sample.img'),
            'rat_test', 'gdal')
        rat = get_rat(raster_layer, 1)
        self.assertTrue(rat.isValid())

        unique_labels = rat_classify(raster_layer, 1, rat, 'EVT_NAME')
        if Qgis.QGIS_VERSION_INT >= 31800:
            self.assertEqual(unique_labels, list(range(1, 60)))
        else:
            self.assertEqual(unique_labels, list(range(0, 59)))

        # Get color map
        color_map = {}
        for klass in raster_layer.renderer().classes():
            color_map[klass.value] = klass.color.name()

        # Two different colors for EVT_NAME
        self.assertEqual(color_map[11.0], '#0000ff')
        self.assertEqual(color_map[12.0], '#9fa1f0')

        # Reclass
        unique_labels = rat_classify(raster_layer, 1, rat, 'NVCSCLASS')
        if Qgis.QGIS_VERSION_INT >= 31800:
            self.assertEqual(unique_labels, [1, 3, 5, 6, 7, 22, 31, 41, 44])
        else:
            self.assertEqual(unique_labels, [0, 2, 4, 5, 6, 21, 30, 40, 43])

        color_map = {}
        for klass in raster_layer.renderer().classes():
            color_map[klass.value] = klass.color.name()

        # Same colors for NVCSCLASS
        self.assertEqual(color_map[11.0], '#0000ff')
        self.assertEqual(color_map[12.0], '#0000ff')

        # Manually change one color
        classes = raster_layer.renderer().classes()
        classes[0].color = QColor(10, 20, 30)

        renderer = QgsPalettedRasterRenderer(raster_layer.dataProvider(), 1,
                                             classes)
        raster_layer.setRenderer(renderer)

        color_map = {}
        for klass in raster_layer.renderer().classes():
            color_map[klass.value] = klass.color.name()

        # Manually changed colors for NVCSCLASS
        self.assertEqual(color_map[11.0], '#0a141e')
        self.assertEqual(color_map[12.0], '#0000ff')

        self.assertTrue(homogenize_colors(raster_layer))

        color_map = {}
        for klass in raster_layer.renderer().classes():
            color_map[klass.value] = klass.color.name()

        # Same colors for NVCSCLASS
        self.assertEqual(color_map[11.0], '#0a141e')
        self.assertEqual(color_map[12.0], '#0a141e')
    def testStartEditingCommitRollBack(self):

        ml = QgsVectorLayer(
            'Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test',
            'memory')
        self.assertTrue(ml.isValid())

        # Layer A geopackage A
        d = QTemporaryDir()
        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'layer_a'
        err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3(
            ml, os.path.join(d.path(), 'test_EditBufferGroup_A.gpkg'),
            QgsCoordinateTransformContext(), options)

        self.assertEqual(err, QgsVectorFileWriter.NoError)
        self.assertTrue(os.path.isfile(newFileName))

        layer_a = QgsVectorLayer(newFileName + '|layername=layer_a')

        self.assertTrue(layer_a.isValid())

        # Layer B geopackage B
        options.layerName = 'layer_b'
        err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3(
            ml, os.path.join(d.path(), 'test_EditBufferGroup_B.gpkg'),
            QgsCoordinateTransformContext(), options)

        self.assertEqual(err, QgsVectorFileWriter.NoError)
        self.assertTrue(os.path.isfile(newFileName))

        layer_b = QgsVectorLayer(newFileName + '|layername=layer_b')

        self.assertTrue(layer_b.isValid())

        # Layer C memory
        layer_c = QgsVectorLayer(
            'Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test',
            'memory')
        self.assertTrue(layer_c.isValid())

        project = QgsProject()
        project.addMapLayers([layer_a, layer_b, layer_c])
        project.setTransactionMode(Qgis.TransactionMode.BufferedGroups)

        editBufferGroup = project.editBufferGroup()

        # Check layers in group
        self.assertIn(layer_a, editBufferGroup.layers())
        self.assertIn(layer_b, editBufferGroup.layers())
        self.assertIn(layer_c, editBufferGroup.layers())

        self.assertFalse(editBufferGroup.isEditing())

        self.assertTrue(editBufferGroup.startEditing())
        self.assertTrue(editBufferGroup.isEditing())
        self.assertTrue(layer_a.editBuffer())
        self.assertTrue(layer_b.editBuffer())
        self.assertTrue(layer_c.editBuffer())
        self.assertEqual(len(editBufferGroup.modifiedLayers()), 0)

        commitErrors = []
        self.assertTrue(editBufferGroup.commitChanges(commitErrors, False))
        self.assertTrue(editBufferGroup.isEditing())
        self.assertTrue(editBufferGroup.commitChanges(commitErrors, True))
        self.assertFalse(editBufferGroup.isEditing())

        self.assertTrue(editBufferGroup.startEditing())
        self.assertTrue(editBufferGroup.isEditing())

        f = QgsFeature(layer_a.fields())
        f.setAttribute('int', 123)
        f.setGeometry(QgsGeometry.fromWkt('point(7 45)'))
        self.assertTrue(layer_a.addFeatures([f]))
        self.assertEqual(len(editBufferGroup.modifiedLayers()), 1)
        self.assertIn(layer_a, editBufferGroup.modifiedLayers())

        # Check feature in layer edit buffer but not in provider till commit
        self.assertEqual(layer_a.featureCount(), 1)
        self.assertEqual(layer_a.dataProvider().featureCount(), 0)

        rollbackErrors = []
        self.assertTrue(editBufferGroup.rollBack(rollbackErrors, False))
        self.assertTrue(editBufferGroup.isEditing())
        self.assertEqual(layer_a.featureCount(), 0)

        self.assertTrue(layer_a.addFeatures([f]))
        self.assertEqual(layer_a.featureCount(), 1)
        self.assertEqual(layer_a.dataProvider().featureCount(), 0)

        self.assertTrue(editBufferGroup.commitChanges(commitErrors, True))
        self.assertFalse(editBufferGroup.isEditing())
        self.assertEqual(layer_a.featureCount(), 1)
        self.assertEqual(layer_a.dataProvider().featureCount(), 1)
Beispiel #4
0
        def _test(is_dbf):

            QgsProject.instance().removeAllMapLayers()

            tmp_dir = QTemporaryDir()
            shutil.copy(
                os.path.join(os.path.dirname(__file__), 'data',
                             'raster-palette.tif'), tmp_dir.path())

            rat_path = os.path.join(
                tmp_dir.path(),
                'raster-palette.tif' + ('.vat.dbf' if is_dbf else '.aux.xml'))
            self.assertFalse(os.path.exists(rat_path))

            raster_layer = QgsRasterLayer(
                os.path.join(tmp_dir.path(), 'raster-palette.tif'), 'rat_test',
                'gdal')
            QgsProject.instance().addMapLayer(raster_layer)

            self.assertTrue(raster_layer.isValid())
            self.assertFalse(can_create_rat(raster_layer))
            self.assertFalse(has_rat(raster_layer))

            band = 1

            # Set renderer
            ramp = QgsRandomColorRamp()
            renderer = QgsPalettedRasterRenderer(
                raster_layer.dataProvider(), 1,
                QgsPalettedRasterRenderer.classDataFromRaster(
                    raster_layer.dataProvider(), band, ramp))
            raster_layer.setRenderer(renderer)
            self.assertTrue(can_create_rat(raster_layer))

            rat = create_rat_from_raster(raster_layer, is_dbf, rat_path)
            self.assertTrue(rat.isValid())

            self.assertEqual(rat.data['Count'], [78, 176, 52])
            self.assertEqual(
                rat.data['Value'],
                [2.257495271713565, 7.037407804695962, 270.4551067154352])
            self.assertEqual(rat.data['A'], [255, 255, 255])
            self.assertNotEqual(rat.data['R'], [0, 0, 0])

            self.assertTrue(rat.save(band))
            self.assertTrue(os.path.exists(rat_path))

            QgsProject.instance().removeMapLayers([raster_layer.id()])
            del (raster_layer)

            self.assertTrue(os.path.exists(rat_path))
            QgsApplication.processEvents()

            # Reload and check
            raster_layer = QgsRasterLayer(
                os.path.join(tmp_dir.path(), 'raster-palette.tif'), 'rat_test',
                'gdal')
            self.assertTrue(raster_layer.isValid())
            self.assertFalse(can_create_rat(raster_layer))
            self.assertTrue(has_rat(raster_layer), rat_path)

            os.unlink(rat_path)
    def testStyles(self):
        """Test that styles for rasters and vectors are kept when setDataSource is called"""

        temp_dir = QTemporaryDir()
        p = QgsProject.instance()
        for f in (
                'bad_layer_raster_test.tfw',
                'bad_layer_raster_test.tiff',
                'bad_layer_raster_test.tiff.aux.xml',
                'bad_layers_test.gpkg',
                'good_layers_test.qgs'):
            copyfile(os.path.join(TEST_DATA_DIR, 'projects', f), os.path.join(temp_dir.path(), f))

        project_path = os.path.join(temp_dir.path(), 'good_layers_test.qgs')
        p = QgsProject().instance()
        p.removeAllMapLayers()
        self.assertTrue(p.read(project_path))
        self.assertEqual(p.count(), 4)

        ms = self.getBaseMapSettings()
        point_a_copy = list(p.mapLayersByName('point_a copy'))[0]
        point_a = list(p.mapLayersByName('point_a'))[0]
        point_b = list(p.mapLayersByName('point_b'))[0]
        raster = list(p.mapLayersByName('bad_layer_raster_test'))[0]
        self.assertTrue(point_a_copy.isValid())
        self.assertTrue(point_a.isValid())
        self.assertTrue(point_b.isValid())
        self.assertTrue(raster.isValid())
        ms.setExtent(QgsRectangle(2.81861, 41.98138, 2.81952, 41.9816))
        ms.setLayers([point_a_copy, point_a, point_b, raster])
        image = renderMapToImage(ms)
        self.assertTrue(image.save(os.path.join(temp_dir.path(), 'expected.png'), 'PNG'))

        point_a_source = point_a.publicSource()
        point_b_source = point_b.publicSource()
        raster_source = raster.publicSource()
        self._change_data_source(point_a, point_a_source, 'ogr')
        # Attention: we are not passing the subset string here:
        self._change_data_source(point_a_copy, point_a_source, 'ogr')
        self._change_data_source(point_b, point_b_source, 'ogr')
        self._change_data_source(raster, raster_source, 'gdal')
        self.assertTrue(image.save(os.path.join(temp_dir.path(), 'actual.png'), 'PNG'))

        self.assertTrue(filecmp.cmp(os.path.join(temp_dir.path(), 'actual.png'), os.path.join(temp_dir.path(), 'expected.png')), False)

        # Now build a bad project
        p.removeAllMapLayers()
        bad_project_path = os.path.join(temp_dir.path(), 'bad_layers_test.qgs')
        with open(project_path, 'r') as infile:
            with open(bad_project_path, 'w+') as outfile:
                outfile.write(infile.read().replace('./bad_layers_test.', './bad_layers_test-BAD_SOURCE.').replace('bad_layer_raster_test.tiff', 'bad_layer_raster_test-BAD_SOURCE.tiff'))

        p.removeAllMapLayers()
        self.assertTrue(p.read(bad_project_path))
        self.assertEqual(p.count(), 4)
        point_a_copy = list(p.mapLayersByName('point_a copy'))[0]
        point_a = list(p.mapLayersByName('point_a'))[0]
        point_b = list(p.mapLayersByName('point_b'))[0]
        raster = list(p.mapLayersByName('bad_layer_raster_test'))[0]
        self.assertFalse(point_a.isValid())
        self.assertFalse(point_a_copy.isValid())
        self.assertFalse(point_b.isValid())
        self.assertFalse(raster.isValid())
        ms.setLayers([point_a_copy, point_a, point_b, raster])
        image = renderMapToImage(ms)
        self.assertTrue(image.save(os.path.join(temp_dir.path(), 'bad.png'), 'PNG'))
        self.assertFalse(filecmp.cmp(os.path.join(temp_dir.path(), 'bad.png'), os.path.join(temp_dir.path(), 'expected.png')), False)

        self._change_data_source(point_a, point_a_source, 'ogr')
        # We are not passing the subset string!!
        self._change_data_source(point_a_copy, point_a_source, 'ogr')
        self._change_data_source(point_b, point_b_source, 'ogr')
        self._change_data_source(raster, raster_source, 'gdal')
        self.assertTrue(point_a.isValid())
        self.assertTrue(point_a_copy.isValid())
        self.assertTrue(point_b.isValid())
        self.assertTrue(raster.isValid())

        ms.setLayers([point_a_copy, point_a, point_b, raster])
        image = renderMapToImage(ms)
        self.assertTrue(image.save(os.path.join(temp_dir.path(), 'actual_fixed.png'), 'PNG'))

        self.assertTrue(filecmp.cmp(os.path.join(temp_dir.path(), 'actual_fixed.png'), os.path.join(temp_dir.path(), 'expected.png')), False)
Beispiel #6
0
    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)
Beispiel #7
0
from qdjango.apps import QGS_SERVER, get_qgs_project
from qdjango.models import (ConstraintExpressionRule,
                            ConstraintSubsetStringRule, Layer, Project,
                            SessionTokenFilter, SessionTokenFilterLayer,
                            SingleLayerConstraint, buildLayerTreeNodeObject)
from qdjango.tests.base import CURRENT_PATH, QdjangoTestBase
from qgis.core import (Qgis, QgsDataSourceUri, QgsProject, QgsProviderRegistry,
                       QgsVectorLayer, QgsWkbTypes)
from qgis.PyQt.QtCore import QTemporaryDir
from qgis.PyQt.QtGui import QImage
from rest_framework import status
from rest_framework.test import APIClient
from vcr.record_mode import RecordMode
from vcr_unittest import VCRMixin

temp_datasource = QTemporaryDir()


@override_settings(CACHES={
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'some',
    }
},
                   LANGUAGE_CODE='en',
                   LANGUAGES=(('en', 'English'), ),
                   DATASOURCE_PATH=temp_datasource.path(),
                   MEDIA_ROOT=temp_datasource.path(),
                   HUEY={'immediate': True})
class OpenrouteserviceTest(VCRMixin, QdjangoTestBase):
    """Test proxy to QgsServer"""
    def test_project_roundtrip(self):
        """Tests that a project with bad layers can be saved and restored"""

        p = QgsProject.instance()
        temp_dir = QTemporaryDir()
        for ext in ('shp', 'dbf', 'shx', 'prj'):
            copyfile(os.path.join(TEST_DATA_DIR, 'lines.%s' % ext), os.path.join(temp_dir.path(), 'lines.%s' % ext))
        copyfile(os.path.join(TEST_DATA_DIR, 'raster', 'band1_byte_ct_epsg4326.tif'), os.path.join(temp_dir.path(), 'band1_byte_ct_epsg4326.tif'))
        copyfile(os.path.join(TEST_DATA_DIR, 'raster', 'band1_byte_ct_epsg4326.tif'), os.path.join(temp_dir.path(), 'band1_byte_ct_epsg4326_copy.tif'))
        l = QgsVectorLayer(os.path.join(temp_dir.path(), 'lines.shp'), 'lines', 'ogr')
        self.assertTrue(l.isValid())

        rl = QgsRasterLayer(os.path.join(temp_dir.path(), 'band1_byte_ct_epsg4326.tif'), 'raster', 'gdal')
        self.assertTrue(rl.isValid())
        rl_copy = QgsRasterLayer(os.path.join(temp_dir.path(), 'band1_byte_ct_epsg4326_copy.tif'), 'raster_copy', 'gdal')
        self.assertTrue(rl_copy.isValid())
        self.assertTrue(p.addMapLayers([l, rl, rl_copy]))

        # Save project
        project_path = os.path.join(temp_dir.path(), 'project.qgs')
        self.assertTrue(p.write(project_path))

        # Re-load the project, checking for the XML properties
        p.removeAllMapLayers()
        self.assertTrue(p.read(project_path))
        vector = list(p.mapLayersByName('lines'))[0]
        raster = list(p.mapLayersByName('raster'))[0]
        raster_copy = list(p.mapLayersByName('raster_copy'))[0]
        self.assertTrue(vector.originalXmlProperties() != '')
        self.assertTrue(raster.originalXmlProperties() != '')
        self.assertTrue(raster_copy.originalXmlProperties() != '')
        # Test setter
        raster.setOriginalXmlProperties('pippo')
        self.assertEqual(raster.originalXmlProperties(), 'pippo')

        # Now create and invalid project:
        bad_project_path = os.path.join(temp_dir.path(), 'project_bad.qgs')
        with open(project_path, 'r') as infile:
            with open(bad_project_path, 'w+') as outfile:
                outfile.write(infile.read().replace('./lines.shp', './lines-BAD_SOURCE.shp').replace('band1_byte_ct_epsg4326_copy.tif', 'band1_byte_ct_epsg4326_copy-BAD_SOURCE.tif'))

        # Load the bad project
        p.removeAllMapLayers()
        self.assertTrue(p.read(bad_project_path))
        # Check layer is invalid
        vector = list(p.mapLayersByName('lines'))[0]
        raster = list(p.mapLayersByName('raster'))[0]
        raster_copy = list(p.mapLayersByName('raster_copy'))[0]
        self.assertIsNotNone(vector.dataProvider())
        self.assertIsNotNone(raster.dataProvider())
        self.assertIsNotNone(raster_copy.dataProvider())
        self.assertFalse(vector.isValid())
        self.assertFalse(raster_copy.isValid())
        # Try a getFeatures
        self.assertEqual([f for f in vector.getFeatures()], [])
        self.assertTrue(raster.isValid())
        self.assertEqual(vector.providerType(), 'ogr')

        # Save the project
        bad_project_path2 = os.path.join(temp_dir.path(), 'project_bad2.qgs')
        p.write(bad_project_path2)
        # Re-save the project, with fixed paths
        good_project_path = os.path.join(temp_dir.path(), 'project_good.qgs')
        with open(bad_project_path2, 'r') as infile:
            with open(good_project_path, 'w+') as outfile:
                outfile.write(infile.read().replace('./lines-BAD_SOURCE.shp', './lines.shp').replace('band1_byte_ct_epsg4326_copy-BAD_SOURCE.tif', 'band1_byte_ct_epsg4326_copy.tif'))

        # Load the good project
        p.removeAllMapLayers()
        self.assertTrue(p.read(good_project_path))
        # Check layer is valid
        vector = list(p.mapLayersByName('lines'))[0]
        raster = list(p.mapLayersByName('raster'))[0]
        raster_copy = list(p.mapLayersByName('raster_copy'))[0]
        self.assertTrue(vector.isValid())
        self.assertTrue(raster.isValid())
        self.assertTrue(raster_copy.isValid())
Beispiel #9
0
    def testExportImport(self):
        p = QgsProject()
        manager = QgsBookmarkManager.createProjectBasedManager(p)
        manager2 = QgsBookmarkManager.createProjectBasedManager(p)
        manager3 = QgsBookmarkManager.createProjectBasedManager(p)

        tmpDir = QTemporaryDir()
        tmpFile = "{}/bookmarks.xml".format(tmpDir.path())

        # no managers
        self.assertTrue(QgsBookmarkManager.exportToFile(tmpFile, []))
        self.assertTrue(manager3.importFromFile(tmpFile))
        self.assertFalse(manager3.bookmarks())

        # no bookmarks
        self.assertTrue(QgsBookmarkManager.exportToFile(tmpFile, [manager]))
        self.assertTrue(manager3.importFromFile(tmpFile))
        self.assertFalse(manager3.bookmarks())

        # add a bunch of bookmarks
        b = QgsBookmark()
        b.setId('1')
        b.setName('b1')
        b.setGroup('g1')
        b.setExtent(
            QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41),
                                   QgsCoordinateReferenceSystem('EPSG:4326')))

        b2 = QgsBookmark()
        b2.setId('2')
        b2.setName('b2')
        b2.setExtent(
            QgsReferencedRectangle(QgsRectangle(12, 22, 32, 42),
                                   QgsCoordinateReferenceSystem('EPSG:4326')))

        b3 = QgsBookmark()
        b3.setId('3')
        b3.setName('b3')
        b3.setGroup('g1')
        b3.setExtent(
            QgsReferencedRectangle(QgsRectangle(32, 32, 33, 43),
                                   QgsCoordinateReferenceSystem('EPSG:4326')))

        manager.addBookmark(b)
        manager.addBookmark(b2)
        manager2.addBookmark(b3)

        # export one manager's bookmarks
        self.assertTrue(QgsBookmarkManager.exportToFile(tmpFile, [manager]))
        self.assertTrue(manager3.importFromFile(tmpFile))
        self.assertEqual([(b.name(), b.extent())
                          for b in manager3.bookmarks()],
                         [(b.name(), b.extent()) for b in [b, b2]])

        manager3.clear()
        # export both manager's bookmarks
        self.assertTrue(
            QgsBookmarkManager.exportToFile(tmpFile, [manager, manager2]))
        self.assertTrue(manager3.importFromFile(tmpFile))
        self.assertEqual([(b.name(), b.extent())
                          for b in manager3.bookmarks()],
                         [(b.name(), b.extent()) for b in [b, b2, b3]])

        manager3.clear()
        # restrict to group
        self.assertTrue(
            QgsBookmarkManager.exportToFile(tmpFile, [manager, manager2],
                                            'g1'))
        self.assertTrue(manager3.importFromFile(tmpFile))
        self.assertEqual([(b.name(), b.extent())
                          for b in manager3.bookmarks()],
                         [(b.name(), b.extent()) for b in [b, b3]])
    def test_wms_getprint_legend(self):
        """Test project has 2 layer: red and green and five templates:
            red: follow map theme red
            green: follow map theme green
            blank: no map theme
            full: follow map theme full with both layer
            falsegreen : follow map theme falsegreen (visible layer : green but with blue style)
        """

        tmp_dir = QTemporaryDir()
        shutil.copyfile(
            os.path.join(unitTestDataPath('qgis_server'),
                         'test_project_legend.qgs'),
            os.path.join(tmp_dir.path(), 'test_project_legend.qgs'))
        shutil.copyfile(
            os.path.join(unitTestDataPath('qgis_server'),
                         'test_project_legend.gpkg'),
            os.path.join(tmp_dir.path(), 'test_project_legend.gpkg'))

        project = QgsProject()
        self.assertTrue(
            project.read(
                os.path.join(tmp_dir.path(), 'test_project_legend.qgs')))

        params = {
            "SERVICE": "WMS",
            "VERSION": "1.3",
            "REQUEST": "GetPrint",
            "TEMPLATE": "blank",
            "FORMAT": "png",
            "LAYERS": "",
            "map0:EXTENT": "778000,5600000,836000,5650000",
            "map0:SCALE": "281285",
            "map0:LAYERS": "red",
            "CRS": "EPSG:3857",
            "DPI": '72'
        }

        ######################################################
        # Template legend tests
        # Legend symbol are displayed at coordinates :
        #   First item  : 600 x , 40 y
        #   Second item : 600 x , 60 y

        # blank template, no theme, no LAYERS, specified map0:LAYERS is red
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Only the red layer is displayed, there is no second item
        self._assertRed(image.pixelColor(600, 40))
        self._assertWhite(image.pixelColor(600, 60))

        # blank template, no LAYERS, specified map0:LAYERS is green
        params["map0:LAYERS"] = "green"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Only the green layer is displayed, there is no second item
        self._assertGreen(image.pixelColor(600, 40))
        self._assertWhite(image.pixelColor(600, 60))

        # blank template
        params["map0:LAYERS"] = ""
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Only the red layer is displayed, there is no second item
        self._assertRed(image.pixelColor(600, 40))
        self._assertGreen(image.pixelColor(600, 60))

        # red template, red theme, specified map0:LAYERS is red
        params["TEMPLATE"] = "red"
        params["map0:LAYERS"] = "red"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Only the red layer is displayed, there is no second item
        self._assertRed(image.pixelColor(600, 40))
        self._assertWhite(image.pixelColor(600, 60))

        # red template, red theme, specified map0:LAYERS is green
        params["map0:LAYERS"] = "green"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Only the green layer is displayed, there is no second item
        self._assertGreen(image.pixelColor(600, 40))
        self._assertWhite(image.pixelColor(600, 60))

        # red template, red theme, no map0:LAYERS
        params["map0:LAYERS"] = ""
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Only the red layer is displayed, there is no second item
        self._assertRed(image.pixelColor(600, 40))
        self._assertWhite(image.pixelColor(600, 60))

        # green template, green theme, specified map0:LAYERS is red
        params["TEMPLATE"] = "green"
        params["map0:LAYERS"] = "red"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Only the red layer is displayed, there is no second item
        self._assertRed(image.pixelColor(600, 40))
        self._assertWhite(image.pixelColor(600, 60))

        # green template, green theme, specified map0:LAYERS is green
        params["map0:LAYERS"] = "green"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Only the green layer is displayed, there is no second item
        self._assertGreen(image.pixelColor(600, 40))
        self._assertWhite(image.pixelColor(600, 60))

        # green template, green theme, no map0:LAYERS
        params["map0:LAYERS"] = ""
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Only the green layer is displayed, there is no second item
        self._assertGreen(image.pixelColor(600, 40))
        self._assertWhite(image.pixelColor(600, 60))

        # full template, full theme, specified map0:LAYERS is red
        params["TEMPLATE"] = "full"
        params["map0:LAYERS"] = "red"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Only the red layer is displayed, there is no second item
        self._assertRed(image.pixelColor(600, 40))
        self._assertWhite(image.pixelColor(600, 60))

        # full template, full theme, specified map0:LAYERS is green
        params["map0:LAYERS"] = "green"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Only the green layer is displayed, there is no second item
        self._assertGreen(image.pixelColor(600, 40))
        self._assertWhite(image.pixelColor(600, 60))

        # full template, full theme, no map0:LAYERS
        params["map0:LAYERS"] = ""
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Both red and green layers are displayed
        self._assertRed(image.pixelColor(600, 40))
        self._assertGreen(image.pixelColor(600, 60))

        # falsegreen template, falsegreen theme (green layer is blue), specified map0:LAYERS is red
        params["TEMPLATE"] = "falsegreen"
        params["map0:LAYERS"] = "red"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Only the red layer is displayed, there is no second item
        self._assertRed(image.pixelColor(600, 40))
        self._assertWhite(image.pixelColor(600, 60))

        # full template, full theme, specified map0:LAYERS is green
        params["map0:LAYERS"] = "green"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Only the green layer (in blue) is displayed, there is no second item
        self._assertBlue(image.pixelColor(600, 40))
        self._assertWhite(image.pixelColor(600, 60))

        # full template, full theme, no map0:LAYERS
        params["map0:LAYERS"] = ""
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Only the green layer (in blue) is displayed, there is no second item
        self._assertBlue(image.pixelColor(600, 40))
        self._assertWhite(image.pixelColor(600, 60))
from rest_framework.test import APIClient
from core.models import G3WSpatialRefSys, Group as CoreGroup
from core.utils.qgisapi import get_layer_fids_from_server_fids
from django.core.management import call_command
from qgis.PyQt.QtCore import QTemporaryDir, QDate
from django.core.files import File
from qdjango.models import Layer
from qdjango.utils.data import QgisProject
from editing.models import *
from django.urls import reverse
from rest_framework.test import APIClient
from usersmanage.tests.utils import *

# Makes a copy of test project and data into a temporary directory

temp = QTemporaryDir()
temp_path = temp.path()
DATASOURCE_PATH = os.path.join(temp_path, 'project_data')
editing_path = os.path.join(
    os.path.dirname(__file__), 'data', 'project_data')
project_path = os.path.join(os.path.dirname(__file__), 'data', 'projects')
shutil.copytree(editing_path, DATASOURCE_PATH)
shutil.copytree(project_path, os.path.join(
    temp_path, 'projects'))

QGS_DB = os.path.join(DATASOURCE_PATH, 'editing_test_transaction_group.gpkg')
QGS_FILE = os.path.join(temp_path, 'projects',
                        'editing_test_transaction_group.qgs')
QGS_DB_BACKUP = os.path.join(
    editing_path, 'editing_test_transaction_group.gpkg')
from django.urls import reverse
from guardian.shortcuts import assign_perm, get_anonymous_user
from lxml import etree as et
from qdjango.apps import QGS_SERVER, get_qgs_project
from qdjango.forms import QdjangoProjectForm
from qdjango.models import Layer, Project
from qgis.PyQt.QtCore import QTemporaryDir
from .base import CURRENT_PATH, TEST_BASE_PATH, QdjangoTestBase

logger = logging.getLogger(__name__)

# Run the whole test in a temp MEDIA_ROOT and DATASOURCE_PATH to make sure
# paths are rewritten correctly and without interferences with the existing
# data

TEMP_DIR = QTemporaryDir()
TEMP_PATH = TEMP_DIR.path()
# Directories are separate
DATASOURCE_PATH = os.path.join(TEMP_PATH, 'project_data')
MEDIA_ROOT = os.path.join(TEMP_PATH, 'media_root')
FILE_UPLOAD_TEMP_DIR = os.path.join(TEMP_PATH, 'temp_uploads')
os.mkdir(DATASOURCE_PATH)
os.mkdir(MEDIA_ROOT)
os.mkdir(FILE_UPLOAD_TEMP_DIR)

# Copy all required data
for file in glob.glob(os.path.join(CURRENT_PATH + TEST_BASE_PATH, 'geodata') + '/*.*'):
    shutil.copy(file, DATASOURCE_PATH)


@override_settings(
        def _test(autoTransaction):
            """Test buffer methods within and without transactions

            - create a feature
            - save
            - retrieve the feature
            - change geom and attrs
            - test changes are seen in the buffer
            """

            def _check_feature(wkt):

                f = next(layer_a.getFeatures())
                self.assertEqual(f.geometry().asWkt().upper(), wkt)
                f = list(buffer.addedFeatures().values())[0]
                self.assertEqual(f.geometry().asWkt().upper(), wkt)

            ml = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer', 'test', 'memory')
            self.assertTrue(ml.isValid())

            d = QTemporaryDir()
            options = QgsVectorFileWriter.SaveVectorOptions()
            options.driverName = 'GPKG'
            options.layerName = 'layer_a'
            err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'transaction_test.gpkg'), QgsCoordinateTransformContext(), options)

            self.assertEqual(err, QgsVectorFileWriter.NoError)
            self.assertTrue(os.path.isfile(os.path.join(d.path(), 'transaction_test.gpkg')))

            options.layerName = 'layer_b'
            options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer
            err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'transaction_test.gpkg'), QgsCoordinateTransformContext(), options)

            layer_a = QgsVectorLayer(os.path.join(d.path(), 'transaction_test.gpkg|layername=layer_a'))

            self.assertTrue(layer_a.isValid())

            project = QgsProject()
            project.setAutoTransaction(autoTransaction)
            project.addMapLayers([layer_a])

            ###########################################
            # Tests with a new feature

            self.assertTrue(layer_a.startEditing())
            buffer = layer_a.editBuffer()

            f = QgsFeature(layer_a.fields())
            f.setAttribute('int', 123)
            f.setGeometry(QgsGeometry.fromWkt('point(7 45)'))
            self.assertTrue(layer_a.addFeatures([f]))

            _check_feature('POINT (7 45)')

            # Need to fetch the feature because its ID is NULL (-9223372036854775808)
            f = next(layer_a.getFeatures())

            self.assertEqual(len(buffer.addedFeatures()), 1)
            layer_a.undoStack().undo()
            self.assertEqual(len(buffer.addedFeatures()), 0)
            layer_a.undoStack().redo()
            self.assertEqual(len(buffer.addedFeatures()), 1)
            f = list(buffer.addedFeatures().values())[0]
            self.assertEqual(f.attribute('int'), 123)

            # Now change attribute
            self.assertEqual(buffer.changedAttributeValues(), {})
            layer_a.changeAttributeValue(f.id(), 1, 321)

            self.assertEqual(len(buffer.addedFeatures()), 1)
            # This is surprising: because it was a new feature it has been changed directly
            self.assertEqual(buffer.changedAttributeValues(), {})
            f = list(buffer.addedFeatures().values())[0]
            self.assertEqual(f.attribute('int'), 321)

            layer_a.undoStack().undo()
            self.assertEqual(buffer.changedAttributeValues(), {})
            f = list(buffer.addedFeatures().values())[0]
            self.assertEqual(f.attribute('int'), 123)
            f = next(layer_a.getFeatures())
            self.assertEqual(f.attribute('int'), 123)

            # Change geometry
            f = next(layer_a.getFeatures())
            self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)')))

            _check_feature('POINT (9 43)')
            self.assertEqual(buffer.changedGeometries(), {})

            layer_a.undoStack().undo()

            _check_feature('POINT (7 45)')
            self.assertEqual(buffer.changedGeometries(), {})

            self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)')))
            _check_feature('POINT (9 43)')

            self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(10 44)')))
            _check_feature('POINT (10 44)')

            # This is anothr surprise: geometry edits get collapsed into a single
            # one because they have the same hardcoded id
            layer_a.undoStack().undo()
            _check_feature('POINT (7 45)')

            self.assertTrue(layer_a.commitChanges())

            ###########################################
            # Tests with the existing feature

            # Get the feature
            f = next(layer_a.getFeatures())
            self.assertTrue(f.isValid())
            self.assertEqual(f.attribute('int'), 123)
            self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)')

            self.assertTrue(layer_a.startEditing())
            layer_a.changeAttributeValue(f.id(), 1, 321)
            buffer = layer_a.editBuffer()
            self.assertEqual(buffer.changedAttributeValues(), {1: {1: 321}})
            layer_a.undoStack().undo()
            self.assertEqual(buffer.changedAttributeValues(), {})

            # Change geometry
            self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)')))
            f = next(layer_a.getFeatures())
            self.assertEqual(f.geometry().asWkt().upper(), 'POINT (9 43)')
            self.assertEqual(buffer.changedGeometries()[1].asWkt().upper(), 'POINT (9 43)')
            layer_a.undoStack().undo()
            self.assertEqual(buffer.changedGeometries(), {})
            f = next(layer_a.getFeatures())

            self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)')
            self.assertEqual(buffer.changedGeometries(), {})

            # Delete an existing feature
            self.assertTrue(layer_a.deleteFeature(f.id()))
            with self.assertRaises(StopIteration):
                next(layer_a.getFeatures())
            self.assertEqual(buffer.deletedFeatureIds(), [f.id()])

            layer_a.undoStack().undo()
            self.assertTrue(layer_a.getFeature(f.id()).isValid())
            self.assertEqual(buffer.deletedFeatureIds(), [])

            ###########################################
            # Test delete

            # Delete a new feature
            f = QgsFeature(layer_a.fields())
            f.setAttribute('int', 555)
            f.setGeometry(QgsGeometry.fromWkt('point(8 46)'))
            self.assertTrue(layer_a.addFeatures([f]))
            f = [f for f in layer_a.getFeatures() if f.attribute('int') == 555][0]
            self.assertTrue(f.id() in buffer.addedFeatures())
            self.assertTrue(layer_a.deleteFeature(f.id()))
            self.assertFalse(f.id() in buffer.addedFeatures())
            self.assertFalse(f.id() in buffer.deletedFeatureIds())

            layer_a.undoStack().undo()
            self.assertTrue(f.id() in buffer.addedFeatures())

            ###########################################
            # Add attribute

            field = QgsField('attr1', QVariant.String)
            self.assertTrue(layer_a.addAttribute(field))
            self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1)
            self.assertEqual(buffer.addedAttributes(), [field])

            layer_a.undoStack().undo()
            self.assertEqual(layer_a.fields().lookupField(field.name()), -1)
            self.assertEqual(buffer.addedAttributes(), [])

            layer_a.undoStack().redo()
            self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1)
            self.assertEqual(buffer.addedAttributes(), [field])

            self.assertTrue(layer_a.commitChanges())

            ###########################################
            # Remove attribute

            self.assertTrue(layer_a.startEditing())
            buffer = layer_a.editBuffer()

            attr_idx = layer_a.fields().lookupField(field.name())
            self.assertNotEqual(attr_idx, -1)

            self.assertTrue(layer_a.deleteAttribute(attr_idx))
            self.assertEqual(buffer.deletedAttributeIds(), [2])
            self.assertEqual(layer_a.fields().lookupField(field.name()), -1)

            layer_a.undoStack().undo()
            self.assertEqual(buffer.deletedAttributeIds(), [])
            self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx)

            layer_a.undoStack().redo()
            self.assertEqual(buffer.deletedAttributeIds(), [2])
            self.assertEqual(layer_a.fields().lookupField(field.name()), -1)

            self.assertTrue(layer_a.rollBack())

            ###########################################
            # Rename attribute

            self.assertTrue(layer_a.startEditing())

            attr_idx = layer_a.fields().lookupField(field.name())
            self.assertNotEqual(attr_idx, -1)

            self.assertEqual(layer_a.fields().lookupField('new_name'), -1)
            self.assertTrue(layer_a.renameAttribute(attr_idx, 'new_name'))
            self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx)

            layer_a.undoStack().undo()
            self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx)
            self.assertEqual(layer_a.fields().lookupField('new_name'), -1)

            layer_a.undoStack().redo()
            self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx)
            self.assertEqual(layer_a.fields().lookupField(field.name()), -1)
Beispiel #14
0
    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
Beispiel #15
0
    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})
Beispiel #16
0
    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')
Beispiel #17
0
    def test_wms_getprint_maptheme(self):
        """Test project has 2 layer: red and green and three templates:
            red: follow map theme red
            green: follow map theme green
            blank: no map theme
        """

        tmp_dir = QTemporaryDir()
        shutil.copyfile(
            os.path.join(unitTestDataPath('qgis_server'),
                         'test_project_mapthemes.qgs'),
            os.path.join(tmp_dir.path(), 'test_project_mapthemes.qgs'))
        shutil.copyfile(
            os.path.join(unitTestDataPath('qgis_server'),
                         'test_project_mapthemes.gpkg'),
            os.path.join(tmp_dir.path(), 'test_project_mapthemes.gpkg'))

        project = QgsProject()
        self.assertTrue(
            project.read(
                os.path.join(tmp_dir.path(), 'test_project_mapthemes.qgs')))

        params = {
            "SERVICE": "WMS",
            "VERSION": "1.3",
            "REQUEST": "GetPrint",
            "TEMPLATE": "blank",
            "FORMAT": "png",
            "LAYERS": "",
            "map0:EXTENT":
            "44.92867722467413216,7.097696894150993252,45.0714498943264914,7.378188333645007368",
            "map0:LAYERS": "red",
            "CRS": "EPSG:4326",
            "DPI": '72'
        }

        polygon = 'POLYGON((7.09769689415099325 44.92867722467413216, 7.37818833364500737 44.92867722467413216, 7.37818833364500737 45.0714498943264914, 7.09769689415099325 45.0714498943264914, 7.09769689415099325 44.92867722467413216))'

        ######################################################
        # Template map theme tests, no HIGHLIGHT

        # blank template, specified layer is red
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertRed(image.pixelColor(100, 100))

        # blank template, specified layer is green
        params["map0:LAYERS"] = "green"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertGreen(image.pixelColor(100, 100))

        # red template, no specified layers
        params["map0:LAYERS"] = ""
        params["TEMPLATE"] = "red"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertRed(image.pixelColor(100, 100))

        # green template, no specified layers
        params["map0:LAYERS"] = ""
        params["TEMPLATE"] = "green"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertGreen(image.pixelColor(100, 100))

        # green template, specified layer is red
        # This is a conflict situation: the green template map is set to follow green theme
        # but we tell the server to render the red layer, red is what we get.
        params["map0:LAYERS"] = "red"
        params["TEMPLATE"] = "green"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertRed(image.pixelColor(100, 100))

        ######################################################
        # Start HIGHLIGHT tests

        params["TEMPLATE"] = "blank"
        params["map0:LAYERS"] = "red"
        params["map0:HIGHLIGHT_GEOM"] = polygon
        params[
            "map0:HIGHLIGHT_SYMBOL"] = r'<StyledLayerDescriptor><UserStyle><FeatureTypeStyle><Rule><PolygonSymbolizer><Fill><CssParameter name="fill">%230000FF</CssParameter></Fill></PolygonSymbolizer></Rule></FeatureTypeStyle></UserStyle></StyledLayerDescriptor>'

        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertBlue(image.pixelColor(100, 100))

        # Test highlight without layers
        params["TEMPLATE"] = "blank"
        params["map0:LAYERS"] = ""

        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertBlue(image.pixelColor(100, 100))

        # Test highlight on follow theme (issue GH #34178)
        params["TEMPLATE"] = "red"

        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertBlue(image.pixelColor(100, 100))

        # Test highlight on follow theme (issue GH #34178)
        params["TEMPLATE"] = "green"

        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertBlue(image.pixelColor(100, 100))

        # Test highlight on follow theme, but add LAYERS (issue GH #34178)
        params["TEMPLATE"] = "green"
        params["LAYERS"] = "red"

        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertBlue(image.pixelColor(100, 100))
    def test_project_relations(self):
        """Tests that a project with bad layers and relations can be saved with relations"""

        temp_dir = QTemporaryDir()
        p = QgsProject.instance()
        for ext in ('qgs', 'gpkg'):
            copyfile(os.path.join(TEST_DATA_DIR, 'projects', 'relation_reference_test.%s' % ext), os.path.join(temp_dir.path(), 'relation_reference_test.%s' % ext))

        # Load the good project
        project_path = os.path.join(temp_dir.path(), 'relation_reference_test.qgs')
        p.removeAllMapLayers()
        self.assertTrue(p.read(project_path))
        point_a = list(p.mapLayersByName('point_a'))[0]
        point_b = list(p.mapLayersByName('point_b'))[0]
        point_a_source = point_a.publicSource()
        point_b_source = point_b.publicSource()
        self.assertTrue(point_a.isValid())
        self.assertTrue(point_b.isValid())

        # Check relations
        def _check_relations():
            relation = list(p.relationManager().relations().values())[0]
            self.assertTrue(relation.isValid())
            self.assertEqual(relation.referencedLayer().id(), point_b.id())
            self.assertEqual(relation.referencingLayer().id(), point_a.id())

        _check_relations()

        # Now build a bad project
        bad_project_path = os.path.join(temp_dir.path(), 'relation_reference_test_bad.qgs')
        with open(project_path, 'r') as infile:
            with open(bad_project_path, 'w+') as outfile:
                outfile.write(infile.read().replace('./relation_reference_test.gpkg', './relation_reference_test-BAD_SOURCE.gpkg'))

        # Load the bad project
        p.removeAllMapLayers()
        self.assertTrue(p.read(bad_project_path))
        point_a = list(p.mapLayersByName('point_a'))[0]
        point_b = list(p.mapLayersByName('point_b'))[0]
        self.assertFalse(point_a.isValid())
        self.assertFalse(point_b.isValid())

        # This fails because relations are not valid anymore
        with self.assertRaises(AssertionError):
            _check_relations()

        # Changing data source, relations should be restored:
        point_a.setDataSource(point_a_source, 'point_a', 'ogr')
        point_b.setDataSource(point_b_source, 'point_b', 'ogr')
        self.assertTrue(point_a.isValid())
        self.assertTrue(point_b.isValid())

        # Check if relations were restored
        _check_relations()

        # Reload the bad project
        p.removeAllMapLayers()
        self.assertTrue(p.read(bad_project_path))
        point_a = list(p.mapLayersByName('point_a'))[0]
        point_b = list(p.mapLayersByName('point_b'))[0]
        self.assertFalse(point_a.isValid())
        self.assertFalse(point_b.isValid())

        # This fails because relations are not valid anymore
        with self.assertRaises(AssertionError):
            _check_relations()

        # Save the bad project
        bad_project_path2 = os.path.join(temp_dir.path(), 'relation_reference_test_bad2.qgs')
        p.write(bad_project_path2)

        # Now fix the bad project
        bad_project_path_fixed = os.path.join(temp_dir.path(), 'relation_reference_test_bad_fixed.qgs')
        with open(bad_project_path2, 'r') as infile:
            with open(bad_project_path_fixed, 'w+') as outfile:
                outfile.write(infile.read().replace('./relation_reference_test-BAD_SOURCE.gpkg', './relation_reference_test.gpkg'))

        # Load the fixed project
        p.removeAllMapLayers()
        self.assertTrue(p.read(bad_project_path_fixed))
        point_a = list(p.mapLayersByName('point_a'))[0]
        point_b = list(p.mapLayersByName('point_b'))[0]
        point_a_source = point_a.publicSource()
        point_b_source = point_b.publicSource()
        self.assertTrue(point_a.isValid())
        self.assertTrue(point_b.isValid())
        _check_relations()
        def _test(autoTransaction):
            """Test buffer methods within and without transactions

            - create a feature
            - save
            - retrieve the feature
            - change geom and attrs
            - test changes are seen in the buffer
            """
            def _check_feature(wkt):

                f = next(layer_a.getFeatures())
                self.assertEqual(f.geometry().asWkt().upper(), wkt)
                f = list(buffer.addedFeatures().values())[0]
                self.assertEqual(f.geometry().asWkt().upper(), wkt)

            ml = QgsVectorLayer(
                'Point?crs=epsg:4326&field=int:integer&field=int2:integer',
                'test', 'memory')
            self.assertTrue(ml.isValid())

            d = QTemporaryDir()
            options = QgsVectorFileWriter.SaveVectorOptions()
            options.driverName = 'GPKG'
            options.layerName = 'layer_a'
            err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3(
                ml, os.path.join(d.path(), 'transaction_test.gpkg'),
                QgsCoordinateTransformContext(), options)

            self.assertEqual(err, QgsVectorFileWriter.NoError)
            self.assertTrue(os.path.isfile(newFileName))

            layer_a = QgsVectorLayer(newFileName + '|layername=layer_a')

            self.assertTrue(layer_a.isValid())

            project = QgsProject()
            project.setAutoTransaction(autoTransaction)
            project.addMapLayers([layer_a])

            ###########################################
            # Tests with a new feature

            self.assertTrue(layer_a.startEditing())
            buffer = layer_a.editBuffer()

            f = QgsFeature(layer_a.fields())
            f.setAttribute('int', 123)
            f.setGeometry(QgsGeometry.fromWkt('point(7 45)'))
            self.assertTrue(layer_a.addFeatures([f]))

            _check_feature('POINT (7 45)')

            # Need to fetch the feature because its ID is NULL (-9223372036854775808)
            f = next(layer_a.getFeatures())

            self.assertEqual(len(buffer.addedFeatures()), 1)
            layer_a.undoStack().undo()
            self.assertEqual(len(buffer.addedFeatures()), 0)
            layer_a.undoStack().redo()
            self.assertEqual(len(buffer.addedFeatures()), 1)
            f = list(buffer.addedFeatures().values())[0]
            self.assertEqual(f.attribute('int'), 123)

            # Now change attribute
            self.assertEqual(buffer.changedAttributeValues(), {})
            spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged)
            layer_a.changeAttributeValue(f.id(), 1, 321)
            self.assertEqual(len(spy_attribute_changed), 1)
            self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321])

            self.assertEqual(len(buffer.addedFeatures()), 1)
            # This is surprising: because it was a new feature it has been changed directly
            self.assertEqual(buffer.changedAttributeValues(), {})
            f = list(buffer.addedFeatures().values())[0]
            self.assertEqual(f.attribute('int'), 321)

            spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged)
            layer_a.undoStack().undo()
            self.assertEqual(len(spy_attribute_changed), 1)
            self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 123])
            self.assertEqual(buffer.changedAttributeValues(), {})
            f = list(buffer.addedFeatures().values())[0]
            self.assertEqual(f.attribute('int'), 123)
            f = next(layer_a.getFeatures())
            self.assertEqual(f.attribute('int'), 123)

            # Change multiple attributes
            spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged)
            layer_a.changeAttributeValues(f.id(), {1: 321, 2: 456})
            self.assertEqual(len(spy_attribute_changed), 2)
            self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321])
            self.assertEqual(spy_attribute_changed[1], [f.id(), 2, 456])
            buffer = layer_a.editBuffer()
            # This is surprising: because it was a new feature it has been changed directly
            self.assertEqual(buffer.changedAttributeValues(), {})

            spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged)
            layer_a.undoStack().undo()
            # This is because QgsVectorLayerUndoCommandChangeAttribute plural
            if not autoTransaction:
                layer_a.undoStack().undo()
            f = next(layer_a.getFeatures())
            self.assertEqual(f.attribute('int'), 123)
            self.assertEqual(f.attribute('int2'), None)
            self.assertEqual(len(spy_attribute_changed), 2)
            self.assertEqual(
                spy_attribute_changed[1 if autoTransaction else 0],
                [f.id(), 2, None])
            self.assertEqual(
                spy_attribute_changed[0 if autoTransaction else 1],
                [f.id(), 1, 123])

            # Change geometry
            f = next(layer_a.getFeatures())
            spy_geometry_changed = QSignalSpy(layer_a.geometryChanged)
            self.assertTrue(
                layer_a.changeGeometry(f.id(),
                                       QgsGeometry.fromWkt('point(9 43)')))
            self.assertTrue(len(spy_geometry_changed), 1)
            self.assertEqual(spy_geometry_changed[0][0], f.id())
            self.assertEqual(spy_geometry_changed[0][1].asWkt(),
                             QgsGeometry.fromWkt('point(9 43)').asWkt())

            _check_feature('POINT (9 43)')
            self.assertEqual(buffer.changedGeometries(), {})

            layer_a.undoStack().undo()

            _check_feature('POINT (7 45)')
            self.assertEqual(buffer.changedGeometries(), {})

            self.assertTrue(
                layer_a.changeGeometry(f.id(),
                                       QgsGeometry.fromWkt('point(9 43)')))
            _check_feature('POINT (9 43)')

            self.assertTrue(
                layer_a.changeGeometry(f.id(),
                                       QgsGeometry.fromWkt('point(10 44)')))
            _check_feature('POINT (10 44)')

            # This is another surprise: geometry edits get collapsed into a single
            # one because they have the same hardcoded id
            layer_a.undoStack().undo()
            _check_feature('POINT (7 45)')

            self.assertTrue(layer_a.commitChanges())

            ###########################################
            # Tests with the existing feature

            # Get the feature
            f = next(layer_a.getFeatures())
            self.assertTrue(f.isValid())
            self.assertEqual(f.attribute('int'), 123)
            self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)')

            # Change single attribute
            self.assertTrue(layer_a.startEditing())
            spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged)
            layer_a.changeAttributeValue(f.id(), 1, 321)
            self.assertEqual(len(spy_attribute_changed), 1)
            self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321])
            buffer = layer_a.editBuffer()
            self.assertEqual(buffer.changedAttributeValues(), {1: {1: 321}})

            f = next(layer_a.getFeatures())
            self.assertEqual(f.attribute(1), 321)

            spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged)
            layer_a.undoStack().undo()
            f = next(layer_a.getFeatures())
            self.assertEqual(f.attribute(1), 123)
            self.assertEqual(len(spy_attribute_changed), 1)
            self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 123])
            self.assertEqual(buffer.changedAttributeValues(), {})

            # Change attributes
            spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged)
            layer_a.changeAttributeValues(f.id(), {1: 111, 2: 654})
            self.assertEqual(len(spy_attribute_changed), 2)
            self.assertEqual(spy_attribute_changed[0], [1, 1, 111])
            self.assertEqual(spy_attribute_changed[1], [1, 2, 654])
            f = next(layer_a.getFeatures())
            self.assertEqual(f.attributes(), [1, 111, 654])
            self.assertEqual(buffer.changedAttributeValues(),
                             {1: {
                                 1: 111,
                                 2: 654
                             }})

            spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged)
            layer_a.undoStack().undo()
            # This is because QgsVectorLayerUndoCommandChangeAttribute plural
            if not autoTransaction:
                layer_a.undoStack().undo()
            self.assertEqual(len(spy_attribute_changed), 2)
            self.assertEqual(
                spy_attribute_changed[0 if autoTransaction else 1],
                [1, 1, 123])
            self.assertEqual(
                spy_attribute_changed[1 if autoTransaction else 0],
                [1, 2, None])
            f = next(layer_a.getFeatures())
            self.assertEqual(f.attributes(), [1, 123, None])
            self.assertEqual(buffer.changedAttributeValues(), {})

            # Change geometry
            spy_geometry_changed = QSignalSpy(layer_a.geometryChanged)
            self.assertTrue(
                layer_a.changeGeometry(f.id(),
                                       QgsGeometry.fromWkt('point(9 43)')))
            self.assertEqual(spy_geometry_changed[0][0], 1)
            self.assertEqual(spy_geometry_changed[0][1].asWkt(),
                             QgsGeometry.fromWkt('point(9 43)').asWkt())

            f = next(layer_a.getFeatures())
            self.assertEqual(f.geometry().asWkt().upper(), 'POINT (9 43)')
            self.assertEqual(buffer.changedGeometries()[1].asWkt().upper(),
                             'POINT (9 43)')

            spy_geometry_changed = QSignalSpy(layer_a.geometryChanged)
            layer_a.undoStack().undo()
            self.assertEqual(spy_geometry_changed[0][0], 1)
            self.assertEqual(spy_geometry_changed[0][1].asWkt(),
                             QgsGeometry.fromWkt('point(7 45)').asWkt())
            self.assertEqual(buffer.changedGeometries(), {})
            f = next(layer_a.getFeatures())

            self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)')
            self.assertEqual(buffer.changedGeometries(), {})

            # Delete an existing feature
            self.assertTrue(layer_a.deleteFeature(f.id()))
            with self.assertRaises(StopIteration):
                next(layer_a.getFeatures())
            self.assertEqual(buffer.deletedFeatureIds(), [f.id()])

            layer_a.undoStack().undo()
            self.assertTrue(layer_a.getFeature(f.id()).isValid())
            self.assertEqual(buffer.deletedFeatureIds(), [])

            ###########################################
            # Test delete

            # Delete a new feature
            f = QgsFeature(layer_a.fields())
            f.setAttribute('int', 555)
            f.setGeometry(QgsGeometry.fromWkt('point(8 46)'))
            self.assertTrue(layer_a.addFeatures([f]))
            f = [
                f for f in layer_a.getFeatures() if f.attribute('int') == 555
            ][0]
            self.assertTrue(f.id() in buffer.addedFeatures())
            self.assertTrue(layer_a.deleteFeature(f.id()))
            self.assertFalse(f.id() in buffer.addedFeatures())
            self.assertFalse(f.id() in buffer.deletedFeatureIds())

            layer_a.undoStack().undo()
            self.assertTrue(f.id() in buffer.addedFeatures())

            ###########################################
            # Add attribute

            field = QgsField('attr1', QVariant.String)
            self.assertTrue(layer_a.addAttribute(field))
            self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1)
            self.assertEqual(buffer.addedAttributes(), [field])

            layer_a.undoStack().undo()
            self.assertEqual(layer_a.fields().lookupField(field.name()), -1)
            self.assertEqual(buffer.addedAttributes(), [])

            layer_a.undoStack().redo()
            self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1)
            self.assertEqual(buffer.addedAttributes(), [field])

            self.assertTrue(layer_a.commitChanges())

            ###########################################
            # Remove attribute

            self.assertTrue(layer_a.startEditing())
            buffer = layer_a.editBuffer()

            attr_idx = layer_a.fields().lookupField(field.name())
            self.assertNotEqual(attr_idx, -1)

            self.assertTrue(layer_a.deleteAttribute(attr_idx))
            self.assertEqual(buffer.deletedAttributeIds(), [attr_idx])
            self.assertEqual(layer_a.fields().lookupField(field.name()), -1)

            layer_a.undoStack().undo()
            self.assertEqual(buffer.deletedAttributeIds(), [])
            self.assertEqual(layer_a.fields().lookupField(field.name()),
                             attr_idx)

            # This is totally broken at least on OGR/GPKG: the rollback
            # does not restore the original fields
            if False:

                layer_a.undoStack().redo()
                self.assertEqual(buffer.deletedAttributeIds(), [attr_idx])
                self.assertEqual(layer_a.fields().lookupField(field.name()),
                                 -1)

                # Rollback!
                self.assertTrue(layer_a.rollBack())

                self.assertIn('attr1', layer_a.dataProvider().fields().names())
                self.assertIn('attr1', layer_a.fields().names())
                self.assertEqual(layer_a.fields().names(),
                                 layer_a.dataProvider().fields().names())

                attr_idx = layer_a.fields().lookupField(field.name())
                self.assertNotEqual(attr_idx, -1)

                self.assertTrue(layer_a.startEditing())
                attr_idx = layer_a.fields().lookupField(field.name())
                self.assertNotEqual(attr_idx, -1)

            ###########################################
            # Rename attribute

            attr_idx = layer_a.fields().lookupField(field.name())
            self.assertEqual(layer_a.fields().lookupField('new_name'), -1)
            self.assertTrue(layer_a.renameAttribute(attr_idx, 'new_name'))
            self.assertEqual(layer_a.fields().lookupField('new_name'),
                             attr_idx)

            layer_a.undoStack().undo()
            self.assertEqual(layer_a.fields().lookupField(field.name()),
                             attr_idx)
            self.assertEqual(layer_a.fields().lookupField('new_name'), -1)

            layer_a.undoStack().redo()
            self.assertEqual(layer_a.fields().lookupField('new_name'),
                             attr_idx)
            self.assertEqual(layer_a.fields().lookupField(field.name()), -1)

            #############################################
            # Try hard to make this fail for transactions
            if autoTransaction:
                self.assertTrue(layer_a.commitChanges())
                self.assertTrue(layer_a.startEditing())
                f = next(layer_a.getFeatures())

                # Do
                for i in range(10):
                    spy_attribute_changed = QSignalSpy(
                        layer_a.attributeValueChanged)
                    layer_a.changeAttributeValue(f.id(), 2, i)
                    self.assertEqual(len(spy_attribute_changed), 1)
                    self.assertEqual(spy_attribute_changed[0], [f.id(), 2, i])
                    buffer = layer_a.editBuffer()
                    self.assertEqual(buffer.changedAttributeValues(),
                                     {f.id(): {
                                          2: i
                                      }})
                    f = next(layer_a.getFeatures())
                    self.assertEqual(f.attribute(2), i)

                # Undo/redo
                for i in range(9):

                    # Undo
                    spy_attribute_changed = QSignalSpy(
                        layer_a.attributeValueChanged)
                    layer_a.undoStack().undo()
                    f = next(layer_a.getFeatures())
                    self.assertEqual(f.attribute(2), 8 - i)
                    self.assertEqual(len(spy_attribute_changed), 1)
                    self.assertEqual(spy_attribute_changed[0],
                                     [f.id(), 2, 8 - i])
                    buffer = layer_a.editBuffer()
                    self.assertEqual(buffer.changedAttributeValues(),
                                     {f.id(): {
                                          2: 8 - i
                                      }})

                    # Redo
                    spy_attribute_changed = QSignalSpy(
                        layer_a.attributeValueChanged)
                    layer_a.undoStack().redo()
                    f = next(layer_a.getFeatures())
                    self.assertEqual(f.attribute(2), 9 - i)
                    self.assertEqual(len(spy_attribute_changed), 1)
                    self.assertEqual(spy_attribute_changed[0],
                                     [f.id(), 2, 9 - i])

                    # Undo again
                    spy_attribute_changed = QSignalSpy(
                        layer_a.attributeValueChanged)
                    layer_a.undoStack().undo()
                    f = next(layer_a.getFeatures())
                    self.assertEqual(f.attribute(2), 8 - i)
                    self.assertEqual(len(spy_attribute_changed), 1)
                    self.assertEqual(spy_attribute_changed[0],
                                     [f.id(), 2, 8 - i])
                    buffer = layer_a.editBuffer()
                    self.assertEqual(buffer.changedAttributeValues(),
                                     {f.id(): {
                                          2: 8 - i
                                      }})

                    # Last check
                    f = next(layer_a.getFeatures())
                    self.assertEqual(f.attribute(2), 8 - i)

                self.assertEqual(buffer.changedAttributeValues(),
                                 {f.id(): {
                                      2: 0
                                  }})
                layer_a.undoStack().undo()
                buffer = layer_a.editBuffer()
                self.assertEqual(buffer.changedAttributeValues(), {})
                f = next(layer_a.getFeatures())
                self.assertEqual(f.attribute(2), None)
Beispiel #20
0
 def test_unzip_file_empty(self):
     outDir = QTemporaryDir()
     rc, files = QgsZipUtils.unzip("", outDir.path())
     self.assertFalse(rc)
Beispiel #21
0
    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()