Beispiel #1
0
    def test_unzip_file_not_exist(self):
        outDir = QTemporaryDir()

        zip = os.path.join(self.zipDir, 'fake.zip')
        rc, files = QgsZipUtils.unzip(zip, outDir.path())

        self.assertFalse(rc)
Beispiel #2
0
    def testSetDataSource(self):
        """Test change data source"""

        temp_dir = QTemporaryDir()
        options = QgsDataProvider.ProviderOptions()
        myPath = os.path.join(unitTestDataPath('raster'),
                              'band1_float32_noct_epsg4326.tif')
        myFileInfo = QFileInfo(myPath)
        myBaseName = myFileInfo.baseName()
        layer = QgsRasterLayer(myPath, myBaseName)
        renderer = QgsSingleBandGrayRenderer(layer.dataProvider(), 2)

        image = layer.previewAsImage(QSize(400, 400))
        self.assertFalse(image.isNull())
        self.assertTrue(image.save(os.path.join(temp_dir.path(), 'expected.png'), "PNG"))

        layer.setDataSource(myPath.replace('4326.tif', '4326-BAD_SOURCE.tif'), 'bad_layer', 'gdal', options)
        self.assertFalse(layer.isValid())
        image = layer.previewAsImage(QSize(400, 400))
        self.assertTrue(image.isNull())

        layer.setDataSource(myPath.replace('4326-BAD_SOURCE.tif', '4326.tif'), 'bad_layer', 'gdal', options)
        self.assertTrue(layer.isValid())
        image = layer.previewAsImage(QSize(400, 400))
        self.assertFalse(image.isNull())
        self.assertTrue(image.save(os.path.join(temp_dir.path(), 'actual.png'), "PNG"))

        self.assertTrue(filecmp.cmp(os.path.join(temp_dir.path(), 'actual.png'), os.path.join(temp_dir.path(), 'expected.png')), False)
Beispiel #3
0
    def test_zip_unzip(self):
        tmpDir = QTemporaryDir()
        tmpFile = "{}/project.qgz".format(tmpDir.path())

        project = QgsProject()

        l0 = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "points.shp"), "points", "ogr")
        l1 = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "lines.shp"), "lines", "ogr")
        project.addMapLayers([l0, l1])

        self.assertTrue(project.write(tmpFile))

        project2 = QgsProject()
        self.assertFalse(project2.isZipped())
        self.assertTrue(project2.fileName() == "")
        self.assertTrue(project2.read(tmpFile))
        self.assertTrue(project2.isZipped())
        self.assertTrue(project2.fileName() == tmpFile)
        layers = project2.mapLayers()

        self.assertEqual(len(layers.keys()), 2)
        self.assertTrue(layers[l0.id()].isValid(), True)
        self.assertTrue(layers[l1.id()].isValid(), True)

        project2.clear()
        self.assertFalse(project2.isZipped())
Beispiel #4
0
    def test_unzip_ok(self):
        outDir = QTemporaryDir()

        zip = os.path.join(self.zipDir, 'testzip.zip')
        rc, files = QgsZipUtils.unzip(zip, outDir.path())

        self.assertTrue(rc)
        self.assertEqual(len(files), 11)
 def testSaveNamedStyle(self):
     layer = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory")
     dir = QTemporaryDir()
     dir_path = dir.path()
     style_path = os.path.join(dir_path, 'my.qml')
     _, result = layer.saveNamedStyle(style_path)
     self.assertTrue(result)
     self.assertTrue(os.path.exists(style_path))
Beispiel #6
0
    def test_zip_filename(self):
        tmpDir = QTemporaryDir()
        tmpFile = "{}/project.qgz".format(tmpDir.path())

        project = QgsProject()
        self.assertFalse(project.write())

        project.setFileName(tmpFile)
        self.assertTrue(project.write())
        self.assertTrue(os.path.isfile(tmpFile))
Beispiel #7
0
    def testProjectTitleWithPeriod(self):
        tmpDir = QTemporaryDir()
        tmpFile = "{}/2.18.21.qgs".format(tmpDir.path())
        tmpFile2 = "{}/qgis-3.2.0.qgs".format(tmpDir.path())

        p0 = QgsProject()
        p0.setFileName(tmpFile)

        p1 = QgsProject()
        p1.setFileName(tmpFile2)

        self.assertEqual(p0.baseName(), '2.18.21')
        self.assertEqual(p1.baseName(), 'qgis-3.2.0')
Beispiel #8
0
    def testWriteEntry(self):

        tmpDir = QTemporaryDir()
        tmpFile = "{}/project.qgs".format(tmpDir.path())

        # zip with existing file
        project = QgsProject()
        query = 'select * from "sample DH" where "sample DH"."Elev" > 130 and "sample DH"."Elev" < 140'
        self.assertTrue(project.writeEntry('myscope', 'myentry', query))
        self.assertTrue(project.write(tmpFile))

        self.assertTrue(project.read(tmpFile))
        q, ok = project.readEntry('myscope', 'myentry')
        self.assertTrue(ok)
        self.assertEqual(q, query)
Beispiel #9
0
    def test_zip_unzip_ok(self):
        zip = tmpPath()

        f0 = os.path.join(unitTestDataPath(), 'multipoint.shp')
        f1 = os.path.join(unitTestDataPath(), 'lines.shp')
        f2 = os.path.join(unitTestDataPath(), 'joins.qgs')

        rc = QgsZipUtils.zip(zip, [f0, f1, f2])
        self.assertTrue(rc)

        outDir = QTemporaryDir()
        rc, files = QgsZipUtils.unzip(zip, outDir.path())

        self.assertTrue(rc)
        self.assertEqual(len(files), 3)
Beispiel #10
0
    def test_zip_new_project(self):
        tmpDir = QTemporaryDir()
        tmpFile = "{}/project.qgz".format(tmpDir.path())

        # zip with existing file
        open(tmpFile, 'a').close()

        project = QgsProject()
        self.assertTrue(project.write(tmpFile))

        # zip with non existing file
        os.remove(tmpFile)

        project = QgsProject()
        self.assertTrue(project.write(tmpFile))
        self.assertTrue(os.path.isfile(tmpFile))
Beispiel #11
0
    def testPalPropertiesReadWrite(self):
        tmpDir = QTemporaryDir()
        tmpFile = "{}/project.qgs".format(tmpDir.path())

        s0 = QgsLabelingEngineSettings()
        s0.setNumCandidatePositions(3, 33, 333)

        p0 = QgsProject()
        p0.setFileName(tmpFile)
        p0.setLabelingEngineSettings(s0)
        p0.write()

        p1 = QgsProject()
        p1.read(tmpFile)

        s1 = p1.labelingEngineSettings()
        candidates = s1.numCandidatePositions()

        self.assertEqual(candidates[0], 3)
        self.assertEqual(candidates[1], 33)
        self.assertEqual(candidates[2], 333)
    def test_wms_getprint_legend(self):
        """Test project has 2 layer: red and green and five templates:
            red: follow map theme red
            green: follow map theme green
            blank: no map theme
            full: follow map theme full with both layer
            falsegreen : follow map theme falsegreen (visible layer : green but with blue style)
        """

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        image = QImage.fromData(response.body(), "PNG")
        # Only the green layer (in blue) is displayed, there is no second item
        self._assertBlue(image.pixelColor(600, 40))
        self._assertWhite(image.pixelColor(600, 60))
class TestRATModel(TestCase):
    @classmethod
    def setUpClass(cls):

        cls.qgs = QgsApplication([], False)
        cls.qgs.initQgis()

    def setUp(self):

        self.tmp_dir = QTemporaryDir()
        self.tmp_path = os.path.join(self.tmp_dir.path(), 'data')

        shutil.copytree(os.path.join(os.path.dirname(__file__), 'data'),
                        self.tmp_path)

        self.raster_layer = QgsRasterLayer(
            os.path.join(
                self.tmp_path,
                'NBS_US5PSMBE_20200923_0_generalized_p.source_information.tiff'
            ), 'rat_test', 'gdal')
        self.assertTrue(self.raster_layer.isValid())

        self.raster_layer_color = QgsRasterLayer(
            os.path.join(self.tmp_path, 'ExistingVegetationTypes_sample.img'),
            'rat_test', 'gdal')
        self.assertTrue(self.raster_layer_color.isValid())

    def test_insert_column(self):

        rat = get_rat(self.raster_layer, 1)
        self.assertTrue(rat.isValid())

        model = RATModel(rat)
        tester = QAbstractItemModelTester(
            model, QAbstractItemModelTester.FailureReportingMode.Warning)
        column_count = model.columnCount(QModelIndex())
        field = RATField('f1', gdal.GFU_Generic, gdal.GFT_String)
        self.assertTrue(model.insert_column(3, field)[0])
        self.assertEqual(model.columnCount(QModelIndex()), column_count + 1)
        self.assertEqual(model.headers.index('f1'), 3)

        # Error
        field = RATField('f1', gdal.GFU_Generic, gdal.GFT_String)
        self.assertFalse(model.insert_column(3, field)[0])
        self.assertEqual(model.columnCount(QModelIndex()), column_count + 1)

    def test_insert_column_color(self):

        rat = get_rat(self.raster_layer_color, 1)
        self.assertTrue(rat.isValid())

        model = RATModel(rat)
        tester = QAbstractItemModelTester(
            model, QAbstractItemModelTester.FailureReportingMode.Warning)
        column_count = model.columnCount(QModelIndex())
        field = RATField('f1', gdal.GFU_Generic, gdal.GFT_String)
        self.assertTrue(model.insert_column(3, field)[0])
        self.assertEqual(model.columnCount(QModelIndex()), column_count + 1)
        self.assertEqual(model.headers.index('f1'), 3)

        # Error
        field = RATField('f1', gdal.GFU_Generic, gdal.GFT_String)
        self.assertFalse(model.insert_column(3, field)[0])
        self.assertEqual(model.columnCount(QModelIndex()), column_count + 1)

    def test_remove_column(self):

        rat = get_rat(self.raster_layer, 1)
        self.assertTrue(rat.isValid())

        model = RATModel(rat)
        tester = QAbstractItemModelTester(
            model, QAbstractItemModelTester.FailureReportingMode.Warning)
        column_count = model.columnCount(QModelIndex())
        self.assertFalse(model.remove_column(0)[0])
        self.assertFalse(model.remove_column(1)[0])
        self.assertTrue(model.remove_column(2)[0])
        self.assertEqual(model.columnCount(QModelIndex()), column_count - 1)

    def test_edit_color(self):

        rat = get_rat(self.raster_layer_color, 1)
        model = RATModel(rat)
        tester = QAbstractItemModelTester(
            model, QAbstractItemModelTester.FailureReportingMode.Warning)

        index = model.index(0, 0)
        value = QColor(Qt.magenta)
        model.setData(index, value)

        self.assertEqual(model.data(index, Qt.BackgroundColorRole), value)

    def test_remove_color(self):

        rat = get_rat(self.raster_layer_color, 1)
        model = RATModel(rat)
        tester = QAbstractItemModelTester(
            model, QAbstractItemModelTester.FailureReportingMode.Warning)

        self.assertTrue({'R', 'G', 'B'}.issubset(rat.keys))
        self.assertTrue({'R', 'G', 'B'}.issubset(model.headers))
        self.assertTrue(model.has_color)
        column_count = model.columnCount(QModelIndex())
        self.assertEqual(column_count, 17)

        # Remove colors
        self.assertTrue(model.remove_color())
        self.assertEqual(model.columnCount(QModelIndex()), column_count - 4)

        self.assertFalse(rat.has_color)
        self.assertFalse(model.has_color)
        self.assertFalse({'R', 'G', 'B'}.issubset(rat.keys))
        self.assertFalse({'R', 'G', 'B'}.issubset(model.headers))

        # Add color back (with alpha)
        self.assertTrue(model.insert_color(2))
        self.assertEqual(model.columnCount(QModelIndex()), column_count + 1)
        self.assertTrue({'R', 'G', 'B'}.issubset(rat.keys))
        self.assertTrue({'R', 'G', 'B'}.issubset(model.headers))
        self.assertTrue(rat.has_color)
        self.assertTrue(model.has_color)
        self.assertTrue(RAT_COLOR_HEADER_NAME in rat.keys)

    def test_add_remove_row(self):
        def _test(raster_layer):

            rat = get_rat(self.raster_layer_color, 1)
            model = RATModel(rat)
            tester = QAbstractItemModelTester(
                model, QAbstractItemModelTester.FailureReportingMode.Warning)

            row_count = model.rowCount(QModelIndex())
            value_index = 1 if model.has_color else 0
            value_0 = model.data(model.index(0, value_index, QModelIndex()))
            value_last = model.data(
                model.index(row_count - 1, value_index, QModelIndex()))

            # Insert first
            self.assertTrue(model.insert_row(0))
            self.assertEqual(model.rowCount(QModelIndex()), row_count + 1)
            self.assertNotEqual(
                model.data(model.index(0, value_index, QModelIndex())),
                value_0)
            self.assertEqual(
                model.data(model.index(0, value_index, QModelIndex())), 0)

            self.assertTrue(model.remove_row(0))
            self.assertEqual(model.rowCount(QModelIndex()), row_count)
            self.assertEqual(
                model.data(model.index(0, value_index, QModelIndex())),
                value_0)

            # Insert last
            self.assertTrue(model.insert_row(row_count))
            self.assertEqual(model.rowCount(QModelIndex()), row_count + 1)
            self.assertNotEqual(
                model.data(model.index(row_count, value_index, QModelIndex())),
                value_last)
            self.assertEqual(
                model.data(model.index(row_count, value_index, QModelIndex())),
                0)
            self.assertEqual(
                model.data(
                    model.index(row_count - 1, value_index, QModelIndex())),
                value_last)

            self.assertTrue(model.remove_row(row_count))
            self.assertEqual(model.rowCount(QModelIndex()), row_count)
            self.assertEqual(
                model.data(
                    model.index(row_count - 1, value_index, QModelIndex())),
                value_last)

        _test(self.raster_layer)
        _test(self.raster_layer_color)

    def test_header_tooltip(self):

        rat = get_rat(self.raster_layer_color, 1)
        model = RATModel(rat)
        tooltip = model.getHeaderTooltip(1)
        self.assertIn('<dt>Role</dt><dd>Class value(min=max)</dd>', tooltip)
        self.assertIn('<dt>Type</dt><dd>Integer</dd>', tooltip)
        tooltip = model.getHeaderTooltip(2)
        self.assertIn('<dt>Role</dt><dd>Histogram pixel count</dd>', tooltip)
        self.assertIn('<dt>Type</dt><dd>Integer</dd>', tooltip)
        tooltip = model.getHeaderTooltip(3)
        self.assertIn('<dt>Role</dt><dd>General purpose field</dd>', tooltip)
        self.assertIn('<dt>Type</dt><dd>String</dd>', tooltip)
class TestRATClasses(TestCase):
    @classmethod
    def setUpClass(cls):

        cls.qgs = QgsApplication([], False)
        cls.qgs.initQgis()

    @classmethod
    def tearDownClass(cls):

        cls.qgs.exitQgis()

    def tearDown(self):

        del (self.raster_layer)
        del (self.raster_layer_dbf)
        del (self.raster_layer_athematic)

    def setUp(self):

        self.tmp_dir = QTemporaryDir()
        self.tmp_path = os.path.join(self.tmp_dir.path(), 'data')

        shutil.copytree(os.path.join(os.path.dirname(__file__), 'data'),
                        self.tmp_path)

        self.raster_layer = QgsRasterLayer(
            os.path.join(
                self.tmp_path,
                'NBS_US5PSMBE_20200923_0_generalized_p.source_information.tiff'
            ), 'rat_test', 'gdal')
        self.assertTrue(self.raster_layer.isValid())

        self.raster_layer_dbf = QgsRasterLayer(
            os.path.join(self.tmp_path, 'ExistingVegetationTypes_sample.img'),
            'rat_test', 'gdal')
        self.assertTrue(self.raster_layer_dbf.isValid())

        self.raster_layer_athematic = QgsRasterLayer(
            os.path.join(self.tmp_path, '2x2_1_BAND_FLOAT.tif'), 'rat_test',
            'gdal')
        self.assertTrue(self.raster_layer_athematic.isValid())

    def test_field_usages(self):

        rat = get_rat(self.raster_layer, 1)
        self.assertTrue(rat.isValid())
        self.assertEqual(rat.field_usages, {0, 1, 5})

    def test_insert_column(self):

        rat = get_rat(self.raster_layer, 1)
        self.assertTrue(rat.isValid())
        self.assertEqual(len(rat.keys), 16)
        self.assertEqual(len(rat.keys), len(rat.fields))

        # Not valid insertions
        field = RATField('f1', gdal.GFU_MinMax, gdal.GFT_Real)
        self.assertFalse(rat.insert_column(4, field)[0])

        field = RATField('f1', gdal.GFU_Generic, gdal.GFT_Real)
        self.assertFalse(rat.insert_column(0, field)[0])

        field = RATField('f1', gdal.GFU_Generic, gdal.GFT_Real)
        self.assertFalse(rat.insert_column(1, field)[0])

        field = RATField('f1', gdal.GFU_Generic, gdal.GFT_Real)
        self.assertFalse(rat.insert_column(100, field)[0])

        field = RATField('significant_features', gdal.GFU_Generic,
                         gdal.GFT_Real)
        self.assertFalse(rat.insert_column(4, field)[0])

        # Valid insertions

        field = RATField('f1', gdal.GFU_Generic, gdal.GFT_Real)
        self.assertEqual(field.qgis_type, QVariant.Double)
        self.assertTrue(rat.insert_column(4, field)[0])
        self.assertIn('f1', rat.fields.keys())
        self.assertEqual(len(rat.data['f1']), len(rat.data['Value']))

        field = RATField('f2', gdal.GFU_Generic, gdal.GFT_Integer)
        self.assertEqual(field.qgis_type, QVariant.Int)
        self.assertTrue(rat.insert_column(2, field)[0])
        self.assertIn('f2', rat.fields.keys())
        self.assertEqual(len(rat.data['f2']), len(rat.data['Value']))
        self.assertEqual(rat.data['f2'][0], 0)

        field = RATField('f3', gdal.GFU_Generic, gdal.GFT_String)
        self.assertEqual(field.qgis_type, QVariant.String)
        self.assertTrue(rat.insert_column(len(rat.keys) - 1, field)[0])
        self.assertIn('f3', rat.fields.keys())
        self.assertEqual(len(rat.data['f3']), len(rat.data['Value']))
        self.assertEqual(rat.data['f3'][0], '')

    def test_remove_column(self):

        rat = get_rat(self.raster_layer, 1)
        self.assertTrue(rat.isValid())
        self.assertEqual(len(rat.keys), 16)
        self.assertEqual(len(rat.keys), len(rat.fields))

        # Invalid removals
        self.assertFalse(rat.remove_column('Value')[0])
        self.assertFalse(rat.remove_column('Count')[0])
        self.assertFalse(rat.remove_column('not found')[0])

        # Valid removals
        self.assertTrue(rat.remove_column('data_assessment')[0])
        self.assertEqual(len(rat.keys), 15)
        self.assertEqual(len(rat.keys), len(rat.fields))

    def test_insert_column_dbf(self):

        rat = get_rat(self.raster_layer_dbf, 1)
        self.assertTrue(rat.isValid())
        self.assertEqual(len(rat.keys), 17)
        # has color, so fields are one more than keys
        self.assertEqual(len(rat.keys), len(rat.fields) + 1)

        # Not valid insertions
        field = RATField('f1', gdal.GFU_MinMax, gdal.GFT_Real)
        self.assertFalse(rat.insert_column(4, field)[0])

        field = RATField('f1', gdal.GFU_Generic, gdal.GFT_Real)
        self.assertFalse(rat.insert_column(0, field)[0])

        field = RATField('f1', gdal.GFU_Generic, gdal.GFT_Real)
        self.assertFalse(rat.insert_column(1, field)[0])

        field = RATField('f1', gdal.GFU_Generic, gdal.GFT_Real)
        self.assertFalse(rat.insert_column(100, field)[0])

        field = RATField('SYSTMGRPNA', gdal.GFU_Generic, gdal.GFT_Real)
        self.assertFalse(rat.insert_column(4, field)[0])

        # Valid insertions

        field = RATField('f1', gdal.GFU_Generic, gdal.GFT_Real)
        self.assertEqual(field.qgis_type, QVariant.Double)
        self.assertTrue(rat.insert_column(4, field)[0])
        self.assertIn('f1', rat.fields.keys())
        self.assertEqual(len(rat.data['f1']), len(rat.data['VALUE']))

        field = RATField('f2', gdal.GFU_Generic, gdal.GFT_Integer)
        self.assertEqual(field.qgis_type, QVariant.Int)
        self.assertTrue(rat.insert_column(2, field)[0])
        self.assertIn('f2', rat.fields.keys())
        self.assertEqual(len(rat.data['f2']), len(rat.data['VALUE']))
        self.assertEqual(rat.data['f2'][0], 0)

        field = RATField('f3', gdal.GFU_Generic, gdal.GFT_String)
        self.assertEqual(field.qgis_type, QVariant.String)
        self.assertTrue(rat.insert_column(len(rat.keys) - 1, field)[0])
        self.assertIn('f3', rat.fields.keys())
        self.assertEqual(len(rat.data['f3']), len(rat.data['VALUE']))
        self.assertEqual(rat.data['f3'][0], '')

        field = RATField('R', gdal.GFU_Red, gdal.GFT_Integer)
        self.assertFalse(rat.insert_column(len(rat.keys) - 1, field)[0])

    def test_remove_column_dbf(self):

        rat = get_rat(self.raster_layer_dbf, 1)
        self.assertTrue(rat.isValid())
        self.assertEqual(len(rat.keys), 17)
        self.assertEqual(len(rat.keys), len(rat.fields) + 1)

        # Invalid removals
        self.assertFalse(rat.remove_column('VALUE')[0])
        self.assertFalse(rat.remove_column('COUNT')[0])
        self.assertFalse(rat.remove_column('not found')[0])

        # Valid removals
        self.assertTrue(rat.remove_column('SYSTMGRPNA')[0])
        self.assertEqual(len(rat.keys), 16)
        self.assertEqual(len(rat.keys), len(rat.fields) + 1)

    def test_qgis_features(self):

        rat = get_rat(self.raster_layer_dbf, 1)
        features = rat.qgis_features()
        self.assertEqual(len(features), 59)

        rat = get_rat(self.raster_layer, 1)
        features = rat.qgis_features()
        self.assertEqual(len(features), 27)

    def test_get_set_color(self):

        rat = get_rat(self.raster_layer_dbf, 1)
        color = rat.get_color(0)
        self.assertTrue(color.isValid())

        # Invalid
        self.assertFalse(rat.get_color(-1).isValid())
        self.assertFalse(rat.get_color(100).isValid())

        # Setter
        self.assertTrue(rat.set_color(1, QColor(10, 20, 30, 120)))
        self.assertEqual(rat.get_color(1), QColor(10, 20, 30, 120))

    def test_field_name(self):

        rat = get_rat(self.raster_layer_dbf, 1)

        usages = []
        for field in rat.fields.values():
            if field.usage not in usages:
                usages.append(field.usage)
                self.assertEqual(rat.field_name(field.usage), field.name)

        self.assertEqual(rat.field_name(gdal.GFU_AlphaMax), '')
        self.assertEqual(rat.field_name(gdal.GFU_RedMax), '')
        self.assertEqual(rat.field_name(gdal.GFU_RedMin), '')

    def test_update_color_from_raster(self):

        rat = get_rat(self.raster_layer_dbf, 1)
        self.assertTrue(rat.has_color)
        rat_classify(self.raster_layer_dbf, 1, rat, 'EVT_NAME')

        color_map = {
            klass.value: klass.color
            for klass in self.raster_layer_dbf.renderer().classes()
        }

        # Remove color
        self.assertTrue(rat.remove_color_fields())
        self.assertFalse(rat.has_color)

        # Add color
        result, error_message = rat.insert_color_fields(len(rat.keys) - 1)
        self.assertTrue(result, error_message)
        self.assertTrue(rat.has_color)

        for color in rat.data[RAT_COLOR_HEADER_NAME]:
            self.assertEqual(color, QColor(Qt.black))

        # Update color from raster
        self.assertTrue(rat.update_colors_from_raster(self.raster_layer_dbf))

        value_column = rat.value_columns[0]
        self.assertEqual(value_column, rat.field_name(gdal.GFU_MinMax))

        for row_index in range(len(rat.data[RAT_COLOR_HEADER_NAME])):
            self.assertEqual(rat.data[RAT_COLOR_HEADER_NAME][row_index],
                             color_map[rat.data[value_column][row_index]])

    def test_update_color_from_raster_athematic(self):

        rat = get_rat(self.raster_layer_athematic, 1)
        self.assertTrue(rat.has_color)
        rat_classify(self.raster_layer_athematic, 1, rat, 'Class')

        shader = self.raster_layer_athematic.renderer().shader()
        colorRampShaderFcn = shader.rasterShaderFunction()
        classes = classes = colorRampShaderFcn.colorRampItemList()

        color_map = {klass.value: klass.color for klass in classes}

        # Remove color
        self.assertTrue(rat.remove_color_fields())
        self.assertFalse(rat.has_color)

        # Add color
        result, error_message = rat.insert_color_fields(len(rat.keys) - 1)
        self.assertTrue(result, error_message)
        self.assertTrue(rat.has_color)

        for color in rat.data[RAT_COLOR_HEADER_NAME]:
            self.assertEqual(color, QColor(Qt.black))

        # Update color from raster
        self.assertTrue(
            rat.update_colors_from_raster(self.raster_layer_athematic))

        value_column = rat.value_columns[1]
        self.assertEqual(value_column, rat.field_name(gdal.GFU_Max))

        for row_index in range(len(rat.data[RAT_COLOR_HEADER_NAME])):
            self.assertEqual(rat.data[RAT_COLOR_HEADER_NAME][row_index],
                             color_map[rat.data[value_column][row_index]])

    def test_add_remove_row(self):
        def _test(raster_layer):

            rat = get_rat(raster_layer, 1)
            value_column = rat.value_columns[0]
            self.assertEqual(value_column, rat.field_name(gdal.GFU_MinMax))

            self.assertNotEqual(rat.data[value_column][-1], 0)
            row_count = len(rat.data[value_column])

            result, error_message = rat.insert_row(0)
            self.assertTrue(result)
            self.assertEqual(len(rat.data[value_column]), row_count + 1)
            self.assertEqual(rat.data[value_column][0], 0)

            result, error_message = rat.remove_row(0)
            self.assertTrue(result)
            self.assertEqual(len(rat.data[value_column]), row_count)
            self.assertNotEqual(rat.data[value_column][0], 0)

            last = len(rat.data[value_column])
            result, error_message = rat.insert_row(last)
            self.assertTrue(result)
            self.assertEqual(len(rat.data[value_column]), row_count + 1)
            self.assertEqual(rat.data[value_column][last], 0)

            result, error_message = rat.remove_row(last)
            self.assertTrue(result)
            self.assertEqual(len(rat.data[value_column]), row_count)
            self.assertNotEqual(rat.data[value_column][last - 1], 0)

            # Invalid ranges
            last = len(rat.data[value_column])
            self.assertFalse(rat.insert_row(-1)[0])
            self.assertFalse(rat.insert_row(last + 1)[0])
            self.assertFalse(rat.remove_row(-1)[0])
            self.assertFalse(rat.remove_row(last)[0])

        _test(self.raster_layer_dbf)
        _test(self.raster_layer)

    def test_edit_rat(self):

        raster_layer = QgsRasterLayer(
            os.path.join(self.tmp_path, '2x2_2_BANDS_INT16.tif'), 'rat_test',
            'gdal')
        self.assertTrue(raster_layer.isValid())

        band = 1

        rat = get_rat(raster_layer, band)
        self.assertTrue(rat.isValid())

        self.assertEqual(rat.data['Red'], [0, 100, 200])
        rat.data['Red'] = [111, 222, 123]
        rat.save(band)

        rat = get_rat(raster_layer, band)
        self.assertTrue(rat.isValid())
        self.assertEqual(rat.data['Red'], [111, 222, 123])

    def test_athematic_dbf_roundtrip(self):
        """Test that saving as athematic and reloading does not loose type"""

        rat = get_rat(self.raster_layer_athematic, 1)
        self.assertTrue(rat.has_color)
        self.assertTrue(rat.isValid())
        self.assertEqual(rat.thematic_type, gdal.GRTT_ATHEMATIC)

        # Delete the layer and the PAM file
        raster_source = self.raster_layer_athematic.source()
        pam_path = raster_source + '.aux.xml'
        del (self.raster_layer_athematic)
        os.unlink(pam_path)

        rat.save_as_dbf(raster_source)
        self.assertTrue(os.path.exists(raster_source + '.vat.dbf'))

        self.raster_layer_athematic = QgsRasterLayer(raster_source, 'rat_test',
                                                     'gdal')

        rat_dbf = get_rat(self.raster_layer_athematic, 1)
        self.assertTrue(rat_dbf.has_color)
        self.assertTrue(rat_dbf.isValid())
        self.assertEqual(rat_dbf.thematic_type, gdal.GRTT_ATHEMATIC)
        self.assertEqual(
            rat_dbf.field_usages, {
                gdal.GFU_Generic,
                gdal.GFU_Red,
                gdal.GFU_Green,
                gdal.GFU_Blue,
                gdal.GFU_Min,
                gdal.GFU_Max,
            })

    def test_charset(self):
        """Test that we can save/load non-ASCII chars"""

        rat = get_rat(self.raster_layer, 1)
        self.assertTrue(rat.isValid())

        # Delete the layer and the PAM file
        raster_source = self.raster_layer.source()

        pam_path = raster_source + '.aux.xml'
        dbf_path = raster_source + '.vat.dbf'

        del (self.raster_layer)
        os.unlink(pam_path)

        rat.data['License_Name'][0] = 'Some accented chars èé 😁'

        rat.save_as_dbf(raster_source)
        self.assertTrue(os.path.exists(dbf_path))

        self.raster_layer = QgsRasterLayer(raster_source, 'rat_test', 'gdal')

        rat_dbf = get_rat(self.raster_layer, 1)
        self.assertTrue(rat_dbf.isValid())

        self.assertEqual(rat_dbf.data['License_Na'][0],
                         'Some accented chars èé 😁')

        # Save as XML
        rat.save_as_xml(raster_source, 1)
        self.assertTrue(os.path.exists(pam_path))
        del (self.raster_layer)
        os.unlink(dbf_path)

        self.raster_layer = QgsRasterLayer(raster_source, 'rat_test', 'gdal')

        rat_xml = get_rat(self.raster_layer, 1)
        self.assertTrue(rat_xml.isValid())

        self.assertEqual(rat_xml.data['License_Name'][0],
                         'Some accented chars èé 😁')
Beispiel #15
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 #16
0
    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 #17
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]])
Beispiel #18
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))
Beispiel #19
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 #20
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"""
Beispiel #21
0
 def test_unzip_file_empty(self):
     outDir = QTemporaryDir()
     rc, files = QgsZipUtils.unzip("", outDir.path())
     self.assertFalse(rc)
    def testStartEditingCommitRollBack(self):

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

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

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

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

        self.assertTrue(layer_a.isValid())

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

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

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

        self.assertTrue(layer_b.isValid())

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

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

        editBufferGroup = project.editBufferGroup()

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

        self.assertFalse(editBufferGroup.isEditing())

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

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

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

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

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

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

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

        self.assertTrue(editBufferGroup.commitChanges(commitErrors, True))
        self.assertFalse(editBufferGroup.isEditing())
        self.assertEqual(layer_a.featureCount(), 1)
        self.assertEqual(layer_a.dataProvider().featureCount(), 1)
        def _test(autoTransaction):
            """Test buffer methods within and without transactions

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

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

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

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

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

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

            self.assertTrue(layer_a.isValid())

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

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

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

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

            _check_feature('POINT (7 45)')

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

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

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

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

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

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

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

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

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

            layer_a.undoStack().undo()

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

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

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

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

            self.assertTrue(layer_a.commitChanges())

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            self.assertTrue(layer_a.commitChanges())

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                self.assertEqual(buffer.changedAttributeValues(),
                                 {f.id(): {
                                      2: 0
                                  }})
                layer_a.undoStack().undo()
                buffer = layer_a.editBuffer()
                self.assertEqual(buffer.changedAttributeValues(), {})
                f = next(layer_a.getFeatures())
                self.assertEqual(f.attribute(2), None)
Beispiel #24
0
    def testSymbolicLinkInProjectPath(self):
        """
        Test whether paths to layer sources relative to the project are stored correctly
        when project'name contains a symbolic link.
        In other words, test if project's and layers' names are correctly resolved.
        """
        tmpDir = QTemporaryDir()
        tmpFile = "{}/project.qgs".format(tmpDir.path())
        copyfile(os.path.join(TEST_DATA_DIR, "points.shp"), os.path.join(tmpDir.path(), "points.shp"))
        copyfile(os.path.join(TEST_DATA_DIR, "points.dbf"), os.path.join(tmpDir.path(), "points.dbf"))
        copyfile(os.path.join(TEST_DATA_DIR, "points.shx"), os.path.join(tmpDir.path(), "points.shx"))
        copyfile(os.path.join(TEST_DATA_DIR, "lines.shp"), os.path.join(tmpDir.path(), "lines.shp"))
        copyfile(os.path.join(TEST_DATA_DIR, "lines.dbf"), os.path.join(tmpDir.path(), "lines.dbf"))
        copyfile(os.path.join(TEST_DATA_DIR, "lines.shx"), os.path.join(tmpDir.path(), "lines.shx"))
        copyfile(os.path.join(TEST_DATA_DIR, "landsat_4326.tif"), os.path.join(tmpDir.path(), "landsat_4326.tif"))

        project = QgsProject()

        l0 = QgsVectorLayer(os.path.join(tmpDir.path(), "points.shp"), "points", "ogr")
        l1 = QgsVectorLayer(os.path.join(tmpDir.path(), "lines.shp"), "lines", "ogr")
        l2 = QgsRasterLayer(os.path.join(tmpDir.path(), "landsat_4326.tif"), "landsat", "gdal")
        self.assertTrue(l0.isValid())
        self.assertTrue(l1.isValid())
        self.assertTrue(l2.isValid())
        self.assertTrue(project.addMapLayers([l0, l1, l2]))
        self.assertTrue(project.write(tmpFile))
        del project

        # Create symbolic link to previous project
        tmpDir2 = QTemporaryDir()
        symlinkDir = os.path.join(tmpDir2.path(), "dir")
        os.symlink(tmpDir.path(), symlinkDir)
        tmpFile = "{}/project.qgs".format(symlinkDir)

        # Open project from symmlink and force re-save.
        project = QgsProject()
        self.assertTrue(project.read(tmpFile))
        self.assertTrue(project.write(tmpFile))
        del project

        with open(tmpFile, 'r') as f:
            content = ''.join(f.readlines())
            self.assertTrue('source="./lines.shp"' in content)
            self.assertTrue('source="./points.shp"' in content)
            self.assertTrue('source="./landsat_4326.tif"' in content)
    def testStyles(self):
        """Test that styles for rasters and vectors are kept when setDataSource is called"""

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

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

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

        point_a_source = point_a.publicSource()
        point_b_source = point_b.publicSource()
        raster_source = raster.publicSource()
        point_a.setDataSource(point_a_source, point_a.name(), 'ogr', options)
        point_b.setDataSource(point_b_source, point_b.name(), 'ogr', options)
        raster.setDataSource(raster_source, raster.name(), 'gdal', options)
        self.assertTrue(image.save(os.path.join(temp_dir.path(), 'actual.png'), 'PNG'))

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

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

        self.assertTrue(p.read(bad_project_path))
        self.assertEqual(p.count(), 3)
        point_a = list(p.mapLayersByName('point_a'))[0]
        point_b = list(p.mapLayersByName('point_b'))[0]
        raster = list(p.mapLayersByName('bad_layer_raster_test'))[0]
        self.assertFalse(point_a.isValid())
        self.assertFalse(point_b.isValid())
        self.assertFalse(raster.isValid())

        point_a.setDataSource(point_a_source, point_a.name(), 'ogr', options)
        point_b.setDataSource(point_b_source, point_b.name(), 'ogr', options)
        raster.setDataSource(raster_source, raster.name(), 'gdal', options)
        self.assertTrue(image.save(os.path.join(temp_dir.path(), 'actual_fixed.png'), 'PNG'))

        self.assertTrue(filecmp.cmp(os.path.join(temp_dir.path(), 'actual_fixed.png'), os.path.join(temp_dir.path(), 'expected.png')), False)
Beispiel #26
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 #27
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})
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 #30
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
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')
Beispiel #32
0
    def testSymbolicLinkInProjectPath(self):
        """
        Test whether paths to layer sources relative to the project are stored correctly
        when project'name contains a symbolic link.
        In other words, test if project's and layers' names are correctly resolved.
        """
        tmpDir = QTemporaryDir()
        tmpFile = "{}/project.qgs".format(tmpDir.path())
        copyfile(os.path.join(TEST_DATA_DIR, "points.shp"), os.path.join(tmpDir.path(), "points.shp"))
        copyfile(os.path.join(TEST_DATA_DIR, "points.dbf"), os.path.join(tmpDir.path(), "points.dbf"))
        copyfile(os.path.join(TEST_DATA_DIR, "points.shx"), os.path.join(tmpDir.path(), "points.shx"))
        copyfile(os.path.join(TEST_DATA_DIR, "lines.shp"), os.path.join(tmpDir.path(), "lines.shp"))
        copyfile(os.path.join(TEST_DATA_DIR, "lines.dbf"), os.path.join(tmpDir.path(), "lines.dbf"))
        copyfile(os.path.join(TEST_DATA_DIR, "lines.shx"), os.path.join(tmpDir.path(), "lines.shx"))
        copyfile(os.path.join(TEST_DATA_DIR, "landsat_4326.tif"), os.path.join(tmpDir.path(), "landsat_4326.tif"))

        project = QgsProject()

        l0 = QgsVectorLayer(os.path.join(tmpDir.path(), "points.shp"), "points", "ogr")
        l1 = QgsVectorLayer(os.path.join(tmpDir.path(), "lines.shp"), "lines", "ogr")
        l2 = QgsRasterLayer(os.path.join(tmpDir.path(), "landsat_4326.tif"), "landsat", "gdal")
        self.assertTrue(l0.isValid())
        self.assertTrue(l1.isValid())
        self.assertTrue(l2.isValid())
        self.assertTrue(project.addMapLayers([l0, l1, l2]))
        self.assertTrue(project.write(tmpFile))
        del project

        # Create symbolic link to previous project
        tmpDir2 = QTemporaryDir()
        symlinkDir = os.path.join(tmpDir2.path(), "dir")
        os.symlink(tmpDir.path(), symlinkDir)
        tmpFile = "{}/project.qgs".format(symlinkDir)

        # Open project from symmlink and force re-save.
        project = QgsProject()
        self.assertTrue(project.read(tmpFile))
        self.assertTrue(project.write(tmpFile))
        del project

        with open(tmpFile, 'r') as f:
            content = ''.join(f.readlines())
            self.assertTrue('source="./lines.shp"' in content)
            self.assertTrue('source="./points.shp"' in content)
            self.assertTrue('source="./landsat_4326.tif"' in content)
Beispiel #33
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 #34
0
 def test_unzip_file_empty(self):
     outDir = QTemporaryDir()
     rc, files = QgsZipUtils.unzip("", outDir.path())
     self.assertFalse(rc)
Beispiel #35
0
    def test_project_roundtrip(self):
        """Tests that a project with bad layers can be saved and restored"""

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

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

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

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

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

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

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

        # Load the good project
        p.removeAllMapLayers()
        self.assertTrue(p.read(good_project_path))
        # Check layer is valid
        vector = list(p.mapLayersByName('lines'))[0]
        raster = list(p.mapLayersByName('raster'))[0]
        raster_copy = list(p.mapLayersByName('raster_copy'))[0]
        self.assertTrue(vector.isValid())
        self.assertTrue(raster.isValid())
        self.assertTrue(raster_copy.isValid())
    def test_project_relations(self):
        """Tests that a project with bad layers and relations can be saved with relations"""

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

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

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

        _check_relations()

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

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

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

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

        # Check if relations were restored
        _check_relations()

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

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

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

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

        # Load the fixed project
        self.assertTrue(p.read(bad_project_path_fixed))
        point_a = list(p.mapLayersByName('point_a'))[0]
        point_b = list(p.mapLayersByName('point_b'))[0]
        point_a_source = point_a.publicSource()
        point_b_source = point_b.publicSource()
        self.assertTrue(point_a.isValid())
        self.assertTrue(point_b.isValid())
        _check_relations()
Beispiel #37
0
    def test_project_relations(self):
        """Tests that a project with bad layers and relations can be saved with relations"""

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

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

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

        _check_relations()

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

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

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

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

        # Check if relations were restored
        _check_relations()

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

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

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

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

        # Load the fixed project
        p.removeAllMapLayers()
        self.assertTrue(p.read(bad_project_path_fixed))
        point_a = list(p.mapLayersByName('point_a'))[0]
        point_b = list(p.mapLayersByName('point_b'))[0]
        point_a_source = point_a.publicSource()
        point_b_source = point_b.publicSource()
        self.assertTrue(point_a.isValid())
        self.assertTrue(point_b.isValid())
        _check_relations()
    def test_project_roundtrip(self):
        """Tests that a project with bad layers can be saved and restored"""

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

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

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

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

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

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

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

        # Load the good project
        self.assertTrue(p.read(good_project_path))
        # Check layer is valid
        vector = list(p.mapLayersByName('lines'))[0]
        raster = list(p.mapLayersByName('raster'))[0]
        raster_copy = list(p.mapLayersByName('raster_copy'))[0]
        self.assertTrue(vector.isValid())
        self.assertTrue(raster.isValid())
        self.assertTrue(raster_copy.isValid())
Beispiel #39
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()