コード例 #1
0
    def save_as_geojson(self, output_path: Path) -> Path:
        output_file = Path(output_path, f"{self.resource_name}.geojson")

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = "GeoJSON"
        options.fileEncoding = "utf-8"

        src_crs = self.layer.crs()
        dst_crs = QgsCoordinateReferenceSystem("EPSG:4326")
        options.ct = QgsCoordinateTransform(src_crs, dst_crs,
                                            QgsProject.instance())

        if hasattr(QgsVectorFileWriter, "writeAsVectorFormatV3"):
            writer_, msg, _, _ = QgsVectorFileWriter.writeAsVectorFormatV3(
                self.layer,
                str(output_file),
                QgsProject.instance().transformContext(),
                options,
            )
        else:
            writer_, msg = QgsVectorFileWriter.writeAsVectorFormatV2(
                self.layer,
                str(output_file),
                QgsProject.instance().transformContext(),
                options,
            )
        if msg != "":
            raise DataPackageException(
                tr("Could not write layer {} to disk", output_file),
                bar_msg(tr("Check the log for more details")),
            )

        return output_file
コード例 #2
0
    def _save_layer_to_file(layer: QgsVectorLayer, output_path: Path) -> Path:
        """ Save layer to file"""
        output_file = output_path / f'{layer.name().replace(" ", "")}.csv'
        LOGGER.debug(f'Saving layer to a file {output_file.name}')

        converter = CsvFieldValueConverter(layer)

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = "csv"
        options.fileEncoding = "utf-8"
        options.layerOptions = ["SEPARATOR=COMMA"]
        options.fieldValueConverter = converter

        if hasattr(QgsVectorFileWriter, "writeAsVectorFormatV3"):
            # noinspection PyCallByClass
            writer_, msg, _, _ = QgsVectorFileWriter.writeAsVectorFormatV3(layer, str(output_file),
                                                                           QgsProject.instance().transformContext(),
                                                                           options)
        else:
            writer_, msg = QgsVectorFileWriter.writeAsVectorFormatV2(layer, str(output_file),
                                                                     QgsProject.instance().transformContext(), options)
        if msg:
            raise ProcessInterruptedException(tr('Process ended'),
                                              bar_msg=bar_msg(tr('Exception occurred during data extraction: {}', msg)))
        return output_file
コード例 #3
0
    def testSetBufferedGroupsAfterAutomaticGroups(self):

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

        # Load 2 layer from a geopackage
        d = QTemporaryDir()
        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'layer_a'
        err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3(
            ml, os.path.join(d.path(), 'test_EditBufferGroup.gpkg'),
            QgsCoordinateTransformContext(), options)

        options.layerName = 'layer_b'
        options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer
        err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3(
            ml, os.path.join(d.path(), 'test_EditBufferGroup.gpkg'),
            QgsCoordinateTransformContext(), options)

        layer_a = QgsVectorLayer(newFileName + '|layername=layer_a')
        self.assertTrue(layer_a.isValid())
        layer_b = QgsVectorLayer(newFileName + '|layername=layer_b')
        self.assertTrue(layer_b.isValid())

        project = QgsProject()
        project.addMapLayers([layer_a, layer_b, ml])

        project.setTransactionMode(Qgis.TransactionMode.AutomaticGroups)
        project.setTransactionMode(Qgis.TransactionMode.BufferedGroups)

        project.startEditing()
        success, rollbackErrors = project.rollBack(True)

        self.assertTrue(success)
コード例 #4
0
def write_layer_to_gpkg2(layer, gpkgfile, layername):

    options = QgsVectorFileWriter.SaveVectorOptions()
    from pathlib import Path
    if Path(gpkgfile).exists():
        options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer
    else:
        options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteFile

    # to get rid of spaces in the layer name
    options.layerName = layername
    context = QgsProject.instance().transformContext()

    if hasattr(QgsVectorFileWriter, "writeAsVectorFormatV3"):
        return QgsVectorFileWriter.writeAsVectorFormatV3(layer, gpkgfile, context, options)
    else:
        return QgsVectorFileWriter.writeAsVectorFormatV2(layer, gpkgfile, context, options)
コード例 #5
0
    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)
コード例 #6
0
def exportLayer(layer,
                fields=None,
                to_shapefile=False,
                path=None,
                force=False,
                logger=None):
    logger = logger or feedback
    filepath, _, ext = lyr_utils.getLayerSourceInfo(layer)
    lyr_name, safe_name = lyr_utils.getLayerTitleAndName(layer)
    fields = fields or []
    if layer.type() == layer.VectorLayer:
        if to_shapefile and (force or layer.fields().count() != len(fields)
                             or ext != EXT_SHAPEFILE):
            # Export with Shapefile extension
            ext = EXT_SHAPEFILE
        elif force or ext != EXT_GEOPACKAGE or layer.fields().count() != len(fields) \
                or not isSingleTableGpkg(filepath):
            # Export with GeoPackage extension
            ext = EXT_GEOPACKAGE
        else:
            # No need to export
            logger.logInfo(
                f"No need to export layer {lyr_name} stored at {filepath}")
            return filepath

        # Perform GeoPackage or Shapefile export
        attrs = [
            i for i, f in enumerate(layer.fields())
            if len(fields) == 0 or f.name() in fields
        ]
        output = path or tempFileInSubFolder(safe_name + ext)
        encoding = "UTF-8"
        driver = "ESRI Shapefile" if ext == EXT_SHAPEFILE else "GPKG"
        options = None
        if hasattr(QgsVectorFileWriter, 'SaveVectorOptions'):
            # QGIS v3.x has the SaveVectorOptions object
            options = QgsVectorFileWriter.SaveVectorOptions()
            options.fileEncoding = encoding
            options.attributes = attrs
            options.driverName = driver
        # Make sure that we are using the latest (non-deprecated) write method
        if hasattr(QgsVectorFileWriter, 'writeAsVectorFormatV3'):
            # Use writeAsVectorFormatV3 for QGIS versions >= 3.20 to avoid DeprecationWarnings
            result = QgsVectorFileWriter.writeAsVectorFormatV3(
                layer, output, QgsCoordinateTransformContext(),
                options)  # noqa
        elif hasattr(QgsVectorFileWriter, 'writeAsVectorFormatV2'):
            # Use writeAsVectorFormatV2 for QGIS versions >= 3.10.3 to avoid DeprecationWarnings
            result = QgsVectorFileWriter.writeAsVectorFormatV2(
                layer, output, QgsCoordinateTransformContext(),
                options)  # noqa
        else:
            # Use writeAsVectorFormat for QGIS versions < 3.10.3 for backwards compatibility
            result = QgsVectorFileWriter.writeAsVectorFormat(
                layer,
                output,
                fileEncoding=encoding,
                attributes=attrs,
                driverName=driver)  # noqa
        # Check if first item in result tuple is an error code
        if result[0] == QgsVectorFileWriter.NoError:
            logger.logInfo(f"Layer {lyr_name} exported to {output}")
        else:
            # Dump the result tuple as-is when there are errors (the tuple size depends on the QGIS version)
            logger.logError(
                f"Layer {lyr_name} failed to export.\n\tResult object: {str(result)}"
            )
        return output
    else:
        # Export raster
        if force or not filepath.lower().endswith("tif"):
            output = path or tempFileInSubFolder(safe_name + ".tif")
            writer = QgsRasterFileWriter(output)
            writer.setOutputFormat("GTiff")
            writer.writeRaster(layer.pipe(), layer.width(), layer.height(),
                               layer.extent(), layer.crs())
            del writer
            logger.logInfo(f"Layer {lyr_name} exported to {output}")
            return output
        else:
            logger.logInfo(
                f"No need to export layer {lyr_name} stored at {filepath}")
            return filepath
コード例 #7
0
        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)
コード例 #8
0
    def create_geopackage(project_type: ProjectType, file_path, crs,
                          transform_context) -> None:
        """ Create the geopackage for the given path. """
        encoding = 'UTF-8'
        driver_name = QgsVectorFileWriter.driverForExtension('gpkg')
        for table in project_type.layers:

            layer_path = str(tables[table])
            if layer_path != 'None':
                layer_path += "?crs={}".format(crs.authid())

            vector_layer = QgsVectorLayer(layer_path, table, "memory")
            data_provider = vector_layer.dataProvider()

            fields = QgsFields()

            path = resources_path('data_models', '{}.csv'.format(table))
            csv = load_csv(table, path)

            for csv_feature in csv.getFeatures():
                field = QgsField(name=csv_feature['name'],
                                 type=int(csv_feature['type']))
                field.setComment(csv_feature['comment'])
                field.setAlias(csv_feature['alias'])
                fields.append(field)

            del csv

            # add fields
            data_provider.addAttributes(fields)
            vector_layer.updateFields()

            # set create file layer options
            options = QgsVectorFileWriter.SaveVectorOptions()
            options.driverName = driver_name
            options.fileEncoding = encoding

            options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteFile
            if os.path.exists(file_path):
                options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer

            options.layerName = vector_layer.name()
            options.layerOptions = ['FID=id']

            # write file
            if Qgis.QGIS_VERSION_INT >= 31900:
                write_result, error_message, _, _ = QgsVectorFileWriter.writeAsVectorFormatV3(
                    vector_layer, file_path, transform_context, options)
            else:
                # 3.10 <= QGIS <3.18
                write_result, error_message = QgsVectorFileWriter.writeAsVectorFormatV2(
                    vector_layer, file_path, transform_context, options)

            # result
            if write_result != QgsVectorFileWriter.NoError:
                raise QgsProcessingException(
                    '* ERROR: {}'.format(error_message))

            del fields
            del data_provider
            del vector_layer