コード例 #1
0
ファイル: utils.py プロジェクト: nstoykov/g3w-admin
        def _write_to_ogr(destination_path, new_layer_name, driverName=None):
            """Writes features to new or existing OGR layer"""

            tmp_dir = QTemporaryDir()
            tmp_path = os.path.join(tmp_dir.path(), 'isochrone.json')
            with open(tmp_path, 'w+') as f:
                f.write(geojson)

            tmp_layer = QgsVectorLayer(tmp_path, 'tmp_isochrone', 'ogr')

            if not tmp_layer.isValid():
                raise Exception(
                    _('Cannot create temporary layer for isochrone result.'))

            # Note: shp attribute names are max 10 chars long
            save_options = QgsVectorFileWriter.SaveVectorOptions()
            if driverName is not None:
                save_options.driverName = driverName
            save_options.layerName = new_layer_name
            save_options.fileEncoding = 'utf-8'

            # This is nonsense to me: if the file does not exist the actionOnExistingFile
            # should be ignored instead of raising an error, probable QGIS bug
            if os.path.exists(destination_path):
                # Check if the layer already exists
                layer_exists = QgsVectorFileWriter.targetLayerExists(
                    destination_path, new_layer_name)

                if layer_exists:
                    raise Exception(
                        _('Cannot save isochrone result to destination layer: layer already exists (use "qgis_layer_id" instead)!'
                          ))

                save_options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer

            error_code, error_message = QgsVectorFileWriter.writeAsVectorFormatV2(
                tmp_layer, destination_path,
                project.qgis_project.transformContext(), save_options)

            if error_code != QgsVectorFileWriter.NoError:
                raise Exception(
                    _('Cannot save isochrone result to destination layer: ') +
                    error_message)

            layer_uri = destination_path

            if driverName != 'ESRI Shapefile':
                layer_uri += '|layername=' + new_layer_name

            provider = 'ogr'
            return layer_uri, provider
コード例 #2
0
    def testOverwriteLayer(self):
        """Tests writing a layer with a field value converter."""

        ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory')
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([1])
        provider.addFeatures([ft])

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'test'
        filename = '/vsimem/out.gpkg'
        write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
            ml, filename, options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError,
                         error_message)

        ds = ogr.Open(filename, update=1)
        lyr = ds.GetLayerByName('test')
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 1)
        ds.CreateLayer('another_layer')
        del f
        del lyr
        del ds

        caps = QgsVectorFileWriter.editionCapabilities(filename)
        self.assertTrue((caps & QgsVectorFileWriter.CanAddNewLayer))
        self.assertTrue((caps & QgsVectorFileWriter.CanAppendToExistingLayer))
        self.assertTrue(
            (caps & QgsVectorFileWriter.CanAddNewFieldsToExistingLayer))
        self.assertTrue((caps & QgsVectorFileWriter.CanDeleteLayer))

        self.assertTrue(QgsVectorFileWriter.targetLayerExists(
            filename, 'test'))

        self.assertFalse(
            QgsVectorFileWriter.areThereNewFieldsToCreate(
                filename, 'test', ml, [0]))

        # Test CreateOrOverwriteLayer
        ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory')
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([2])
        provider.addFeatures([ft])

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'test'
        options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer
        filename = '/vsimem/out.gpkg'
        write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
            ml, filename, options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError,
                         error_message)

        ds = ogr.Open(filename)
        lyr = ds.GetLayerByName('test')
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 2)
        # another_layer should still exist
        self.assertIsNotNone(ds.GetLayerByName('another_layer'))
        del f
        del lyr
        del ds

        # Test CreateOrOverwriteFile
        ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory')
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([3])
        provider.addFeatures([ft])

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'test'
        filename = '/vsimem/out.gpkg'
        write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
            ml, filename, options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError,
                         error_message)

        ds = ogr.Open(filename)
        lyr = ds.GetLayerByName('test')
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 3)
        # another_layer should no longer exist
        self.assertIsNone(ds.GetLayerByName('another_layer'))
        del f
        del lyr
        del ds

        # Test AppendToLayerNoNewFields
        ml = QgsVectorLayer('Point?field=firstfield:int&field=secondfield:int',
                            'test', 'memory')
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([4, -10])
        provider.addFeatures([ft])

        self.assertTrue(
            QgsVectorFileWriter.areThereNewFieldsToCreate(
                filename, 'test', ml, [0, 1]))

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'test'
        options.actionOnExistingFile = QgsVectorFileWriter.AppendToLayerNoNewFields
        filename = '/vsimem/out.gpkg'
        write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
            ml, filename, options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError,
                         error_message)

        ds = ogr.Open(filename)
        lyr = ds.GetLayerByName('test')
        self.assertEqual(lyr.GetLayerDefn().GetFieldCount(), 1)
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 3)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 4)
        del f
        del lyr
        del ds

        # Test AppendToLayerAddFields
        ml = QgsVectorLayer('Point?field=firstfield:int&field=secondfield:int',
                            'test', 'memory')
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([5, -1])
        provider.addFeatures([ft])

        self.assertTrue(
            QgsVectorFileWriter.areThereNewFieldsToCreate(
                filename, 'test', ml, [0, 1]))

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'test'
        options.actionOnExistingFile = QgsVectorFileWriter.AppendToLayerAddFields
        filename = '/vsimem/out.gpkg'
        write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
            ml, filename, options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError,
                         error_message)

        ds = ogr.Open(filename)
        lyr = ds.GetLayerByName('test')
        self.assertEqual(lyr.GetLayerDefn().GetFieldCount(), 2)
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 3)
        if hasattr(f, "IsFieldSetAndNotNull"):
            # GDAL >= 2.2
            self.assertFalse(f.IsFieldSetAndNotNull('secondfield'))
        else:
            self.assertFalse(f.IsFieldSet('secondfield'))
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 4)
        if hasattr(f, "IsFieldSetAndNotNull"):
            self.assertFalse(f.IsFieldSetAndNotNull('secondfield'))
        else:
            self.assertFalse(f.IsFieldSet('secondfield'))
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 5)
        self.assertEqual(f['secondfield'], -1)
        del f
        del lyr
        del ds

        gdal.Unlink(filename)
コード例 #3
0
    def testOverwriteLayer(self):
        """Tests writing a layer with a field value converter."""

        ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory')
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([1])
        provider.addFeatures([ft])

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'test'
        filename = '/vsimem/out.gpkg'
        write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
            ml,
            filename,
            options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message)

        ds = ogr.Open(filename, update=1)
        lyr = ds.GetLayerByName('test')
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 1)
        ds.CreateLayer('another_layer')
        del f
        del lyr
        del ds

        caps = QgsVectorFileWriter.editionCapabilities(filename)
        self.assertTrue((caps & QgsVectorFileWriter.CanAddNewLayer))
        self.assertTrue((caps & QgsVectorFileWriter.CanAppendToExistingLayer))
        self.assertTrue((caps & QgsVectorFileWriter.CanAddNewFieldsToExistingLayer))
        self.assertTrue((caps & QgsVectorFileWriter.CanDeleteLayer))

        self.assertTrue(QgsVectorFileWriter.targetLayerExists(filename, 'test'))

        self.assertFalse(QgsVectorFileWriter.areThereNewFieldsToCreate(filename, 'test', ml, [0]))

        # Test CreateOrOverwriteLayer
        ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory')
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([2])
        provider.addFeatures([ft])

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'test'
        options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer
        filename = '/vsimem/out.gpkg'
        write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
            ml,
            filename,
            options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message)

        ds = ogr.Open(filename)
        lyr = ds.GetLayerByName('test')
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 2)
        # another_layer should still exist
        self.assertIsNotNone(ds.GetLayerByName('another_layer'))
        del f
        del lyr
        del ds

        # Test CreateOrOverwriteFile
        ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory')
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([3])
        provider.addFeatures([ft])

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'test'
        filename = '/vsimem/out.gpkg'
        write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
            ml,
            filename,
            options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message)

        ds = ogr.Open(filename)
        lyr = ds.GetLayerByName('test')
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 3)
        # another_layer should no longer exist
        self.assertIsNone(ds.GetLayerByName('another_layer'))
        del f
        del lyr
        del ds

        # Test AppendToLayerNoNewFields
        ml = QgsVectorLayer('Point?field=firstfield:int&field=secondfield:int', 'test', 'memory')
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([4, -10])
        provider.addFeatures([ft])

        self.assertTrue(QgsVectorFileWriter.areThereNewFieldsToCreate(filename, 'test', ml, [0, 1]))

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'test'
        options.actionOnExistingFile = QgsVectorFileWriter.AppendToLayerNoNewFields
        filename = '/vsimem/out.gpkg'
        write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
            ml,
            filename,
            options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message)

        ds = ogr.Open(filename)
        lyr = ds.GetLayerByName('test')
        self.assertEqual(lyr.GetLayerDefn().GetFieldCount(), 1)
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 3)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 4)
        del f
        del lyr
        del ds

        # Test AppendToLayerAddFields
        ml = QgsVectorLayer('Point?field=firstfield:int&field=secondfield:int', 'test', 'memory')
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([5, -1])
        provider.addFeatures([ft])

        self.assertTrue(QgsVectorFileWriter.areThereNewFieldsToCreate(filename, 'test', ml, [0, 1]))

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'test'
        options.actionOnExistingFile = QgsVectorFileWriter.AppendToLayerAddFields
        filename = '/vsimem/out.gpkg'
        write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
            ml,
            filename,
            options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message)

        ds = ogr.Open(filename)
        lyr = ds.GetLayerByName('test')
        self.assertEqual(lyr.GetLayerDefn().GetFieldCount(), 2)
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 3)
        if hasattr(f, "IsFieldSetAndNotNull"):
            # GDAL >= 2.2
            self.assertFalse(f.IsFieldSetAndNotNull('secondfield'))
        else:
            self.assertFalse(f.IsFieldSet('secondfield'))
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 4)
        if hasattr(f, "IsFieldSetAndNotNull"):
            self.assertFalse(f.IsFieldSetAndNotNull('secondfield'))
        else:
            self.assertFalse(f.IsFieldSet('secondfield'))
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 5)
        self.assertEqual(f['secondfield'], -1)
        del f
        del lyr
        del ds

        gdal.Unlink(filename)
コード例 #4
0
    def testOverwriteLayer(self):
        """Tests writing a layer with a field value converter."""

        ml = QgsVectorLayer("Point?field=firstfield:int", "test", "memory")
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([1])
        provider.addFeatures([ft])

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = "GPKG"
        options.layerName = "test"
        filename = "/vsimem/out.gpkg"
        write_result = QgsVectorFileWriter.writeAsVectorFormat(ml, filename, options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError)

        ds = ogr.Open(filename, update=1)
        lyr = ds.GetLayerByName("test")
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f["firstfield"], 1)
        ds.CreateLayer("another_layer")
        del f
        del lyr
        del ds

        caps = QgsVectorFileWriter.editionCapabilities(filename)
        self.assertTrue((caps & QgsVectorFileWriter.CanAddNewLayer))
        self.assertTrue((caps & QgsVectorFileWriter.CanAppendToExistingLayer))
        self.assertTrue((caps & QgsVectorFileWriter.CanAddNewFieldsToExistingLayer))
        self.assertTrue((caps & QgsVectorFileWriter.CanDeleteLayer))

        self.assertTrue(QgsVectorFileWriter.targetLayerExists(filename, "test"))

        self.assertFalse(QgsVectorFileWriter.areThereNewFieldsToCreate(filename, "test", ml, [0]))

        # Test CreateOrOverwriteLayer
        ml = QgsVectorLayer("Point?field=firstfield:int", "test", "memory")
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([2])
        provider.addFeatures([ft])

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = "GPKG"
        options.layerName = "test"
        options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer
        filename = "/vsimem/out.gpkg"
        write_result = QgsVectorFileWriter.writeAsVectorFormat(ml, filename, options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError)

        ds = ogr.Open(filename)
        lyr = ds.GetLayerByName("test")
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f["firstfield"], 2)
        # another_layer should still exist
        self.assertIsNotNone(ds.GetLayerByName("another_layer"))
        del f
        del lyr
        del ds

        # Test CreateOrOverwriteFile
        ml = QgsVectorLayer("Point?field=firstfield:int", "test", "memory")
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([3])
        provider.addFeatures([ft])

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = "GPKG"
        options.layerName = "test"
        filename = "/vsimem/out.gpkg"
        write_result = QgsVectorFileWriter.writeAsVectorFormat(ml, filename, options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError)

        ds = ogr.Open(filename)
        lyr = ds.GetLayerByName("test")
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f["firstfield"], 3)
        # another_layer should no longer exist
        self.assertIsNone(ds.GetLayerByName("another_layer"))
        del f
        del lyr
        del ds

        # Test AppendToLayerNoNewFields
        ml = QgsVectorLayer("Point?field=firstfield:int&field=secondfield:int", "test", "memory")
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([4, -10])
        provider.addFeatures([ft])

        self.assertTrue(QgsVectorFileWriter.areThereNewFieldsToCreate(filename, "test", ml, [0, 1]))

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = "GPKG"
        options.layerName = "test"
        options.actionOnExistingFile = QgsVectorFileWriter.AppendToLayerNoNewFields
        filename = "/vsimem/out.gpkg"
        write_result = QgsVectorFileWriter.writeAsVectorFormat(ml, filename, options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError)

        ds = ogr.Open(filename)
        lyr = ds.GetLayerByName("test")
        self.assertEqual(lyr.GetLayerDefn().GetFieldCount(), 1)
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f["firstfield"], 3)
        f = lyr.GetNextFeature()
        self.assertEqual(f["firstfield"], 4)
        del f
        del lyr
        del ds

        # Test AppendToLayerAddFields
        ml = QgsVectorLayer("Point?field=firstfield:int&field=secondfield:int", "test", "memory")
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([5, -1])
        provider.addFeatures([ft])

        self.assertTrue(QgsVectorFileWriter.areThereNewFieldsToCreate(filename, "test", ml, [0, 1]))

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = "GPKG"
        options.layerName = "test"
        options.actionOnExistingFile = QgsVectorFileWriter.AppendToLayerAddFields
        filename = "/vsimem/out.gpkg"
        write_result = QgsVectorFileWriter.writeAsVectorFormat(ml, filename, options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError)

        ds = ogr.Open(filename)
        lyr = ds.GetLayerByName("test")
        self.assertEqual(lyr.GetLayerDefn().GetFieldCount(), 2)
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f["firstfield"], 3)
        self.assertFalse(f.IsFieldSet("secondfield"))
        f = lyr.GetNextFeature()
        self.assertEqual(f["firstfield"], 4)
        self.assertFalse(f.IsFieldSet("secondfield"))
        f = lyr.GetNextFeature()
        self.assertEqual(f["firstfield"], 5)
        self.assertEqual(f["secondfield"], -1)
        del f
        del lyr
        del ds

        gdal.Unlink(filename)
コード例 #5
0
ファイル: utils.py プロジェクト: nyalldawson/slyr
    def convert_vector_layer(
            layer,  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
            project,
            data_folder,
            feedback,
            conversion_results: ConversionResults,
            change_source_on_error: bool = False,
            verbose_log=False):
        """
        Converts a vector layer to a standard format
        """
        if layer.customProperty('original_uri'):
            uri = layer.customProperty('original_uri')
            if verbose_log:
                feedback.pushDebugInfo(
                    f'Original layer URI from custom properties is {uri}')
        else:
            uri = layer.source()
            if verbose_log:
                feedback.pushDebugInfo(
                    'Original layer URI not found in custom properties')

        source = QgsProviderRegistry.instance().decodeUri(
            layer.providerType(), uri)
        if verbose_log:
            feedback.pushInfo('')

        # older versions of QGIS didn't correctly strip out the subset from the layerName:
        if 'subset' not in source:
            if '|subset=' in source['layerName']:
                if verbose_log:
                    feedback.pushDebugInfo(
                        'Stripping out subset string from layerName: {}'.
                        format(source['layerName']))
                layer_name = source['layerName']
                parts = layer_name.split('|subset=')
                if len(parts) == 2:
                    source['layerName'] = parts[0]
                    if verbose_log:
                        feedback.pushDebugInfo('Cleaned layer name: {}'.format(
                            source['layerName']))
                elif verbose_log:
                    feedback.reportError('Failed to strip subset string!')
            elif '|subset=' in source['path']:
                path = source['path']
                if verbose_log:
                    feedback.pushDebugInfo(
                        'Stripping out subset string from path: {}'.format(
                            source['path']))
                parts = path.split('|subset=')
                if len(parts) == 2:
                    source['path'] = parts[0]
                    if verbose_log:
                        feedback.pushDebugInfo('Cleaned path: {}'.format(
                            source['path']))
                elif verbose_log:
                    feedback.reportError('Failed to strip subset string!')

        # convert to Geopackage
        source_uri = QgsProviderRegistry.instance().encodeUri(
            layer.providerType(), {
                'path': source['path'],
                'layerName': source['layerName']
            })

        # Sometimes the case varies in ArcMap documents, so when comparing to previously converted layers
        # we use a case-insensitive path/layername which is normalized
        result_key = QgsProviderRegistry.instance().encodeUri(
            layer.providerType(), {
                'path': pathlib.Path(
                    source['path']).resolve().as_posix().lower(),
                'layerName': source['layerName'].lower()
            })

        if verbose_log:
            feedback.pushDebugInfo('Converting layer: {} ( {} )'.format(
                source['path'], source['layerName']))
            feedback.pushDebugInfo(f'Cached result key: {result_key}')

        provider_options = QgsDataProvider.ProviderOptions()
        provider_options.transformContext = project.transformContext()
        subset = layer.subsetString()

        # have we maybe already converted this layer??
        if result_key in conversion_results.layer_map:

            previous_results = conversion_results.layer_map[result_key]
            if previous_results.get('error'):
                if verbose_log:
                    feedback.pushDebugInfo(
                        'Already tried to convert this layer, but failed last time, skipping...'
                    )
                    feedback.pushDebugInfo('Restoring stored URI')

                layer.setDataSource(uri, layer.name(), 'ogr', provider_options)
            else:
                if verbose_log:
                    feedback.pushDebugInfo(
                        'Already converted this layer, reusing previous converted path: {} layername: {}'
                        .format(previous_results['destPath'],
                                previous_results['destLayer']))

                layer.setDataSource(
                    QgsProviderRegistry.instance().encodeUri(
                        'ogr', {
                            'path': previous_results['destPath'],
                            'layerName': previous_results['destLayer']
                        }), layer.name(), 'ogr', provider_options)
                if verbose_log:
                    feedback.pushDebugInfo('new source {}'.format(
                        layer.dataProvider().dataSourceUri()))
            if subset:
                if verbose_log:
                    feedback.pushDebugInfo(
                        'Resetting subset string: {}'.format(subset))
                layer.setSubsetString(subset)

            return previous_results

        source_layer = QgsVectorLayer(source_uri, '', layer.providerType())

        path = pathlib.Path(source['path'])

        dest_file_name = ((pathlib.Path(data_folder) /
                           path.stem).with_suffix('.gpkg')).as_posix()
        if dest_file_name not in conversion_results.created_databases:
            # about to use a new file -- let's double-check that it doesn't already exist. We don't want
            # to put layers into a database which we didn't make for this project
            counter = 1
            while pathlib.Path(dest_file_name).exists():
                counter += 1
                dest_file_name = ((pathlib.Path(data_folder) /
                                   (path.stem + '_' + str(counter))
                                   ).with_suffix('.gpkg')).as_posix()
                if dest_file_name in conversion_results.created_databases:
                    break

            if verbose_log:
                feedback.pushDebugInfo(
                    'Creating new destination file {}'.format(dest_file_name))
        elif verbose_log:
            feedback.pushDebugInfo(
                'Reusing existing destination file {}'.format(dest_file_name))

        # now this filename is ok for other layers to be stored in for this conversion
        conversion_results.created_databases.add(dest_file_name)

        layer_name_candidate = source['layerName']
        counter = 1
        while QgsVectorFileWriter.targetLayerExists(dest_file_name,
                                                    layer_name_candidate):
            counter += 1
            layer_name_candidate = '{}_{}'.format(source['layerName'], counter)

        if verbose_log:
            feedback.pushDebugInfo(
                'Target layer name is {}'.format(layer_name_candidate))

        if not source_layer.isValid():
            if verbose_log:
                feedback.reportError('Source layer is not valid')
            if path.exists():
                if verbose_log:
                    feedback.pushDebugInfo('File path DOES exist')

                    test_layer = QgsVectorLayer(path.as_posix())
                    sub_layers = test_layer.dataProvider().subLayers()
                    feedback.pushDebugInfo(
                        f'Readable layers from "{path.as_posix()}" are:')
                    for sub_layer in sub_layers:
                        _, name, count, geom_type, _, _ = sub_layer.split(
                            QgsDataProvider.sublayerSeparator())
                        feedback.pushDebugInfo(
                            f'- "{name}" ({count} features, geometry type {geom_type})'
                        )

            if path.exists() and path.suffix.lower() == '.mdb':
                try:
                    source['layerName'].encode('ascii')
                except UnicodeDecodeError:
                    error = f'''MDB layers with unicode names are not supported by QGIS -- cannot convert "{source['layerName']}"'''
                    if verbose_log:
                        feedback.reportError(error)
                        feedback.pushDebugInfo('Restoring stored URI')

                    layer.setDataSource(uri, layer.name(), 'ogr',
                                        provider_options)
                    if subset:
                        if verbose_log:
                            feedback.pushDebugInfo(
                                'Resetting subset string: {}'.format(subset))
                        layer.setSubsetString(subset)

                    conversion_results.layer_map[result_key] = {'error': error}
                    return conversion_results.layer_map[result_key]

                # maybe a non-spatial table, which can't be read with GDAL < 3.2
                source_layer = None

                if verbose_log:
                    feedback.pushDebugInfo('Layer type is {}'.format(
                        QgsWkbTypes.displayString(layer.wkbType())))

                if layer.wkbType() == QgsWkbTypes.NoGeometry:
                    if verbose_log:
                        feedback.pushDebugInfo(
                            'Attempting fallback for non-spatial tables')
                    try:
                        source_layer = ConversionUtils.convert_mdb_table_to_memory_layer(
                            str(path), source['layerName'])
                        if verbose_log:
                            feedback.pushDebugInfo('Fallback succeeded!')
                    except Exception as e:  # nopep8, pylint: disable=broad-except
                        if verbose_log:
                            feedback.reportError('Fallback failed: {}'.format(
                                str(e)))
                        source_layer = None
                elif verbose_log:
                    feedback.reportError(
                        'Nothing else to try, conversion failed')

                if not source_layer:
                    # here we fake things. We don't leave the original path to the mdb layer intact in the converted
                    # project, as this can cause massive issues with QGIS as it attempts to re-read this path constantly
                    # rather we "pretend" that the conversion was ok and set the broken layer's path to what the gpkg
                    # converted version WOULD have been! It'll still be broken in the converted project (obviously),
                    # but QGIS will no longer try endless to read the MDB and get all hung up on this...
                    conversion_results.layer_map[result_key] = {
                        'sourcePath':
                        source['path'],
                        'sourceLayer':
                        source['layerName'],
                        'destPath':
                        dest_file_name,
                        'destLayer':
                        layer_name_candidate,
                        'error':
                        'Could not open {} ({}) for conversion'.format(
                            source_uri, source['layerName'])
                    }

                    if change_source_on_error:
                        if verbose_log:
                            feedback.pushDebugInfo('Restoring stored URI')

                        layer.setDataSource(uri, layer.name(), 'ogr',
                                            provider_options)
                        if subset:
                            if verbose_log:
                                feedback.pushDebugInfo(
                                    'Resetting subset string: {}'.format(
                                        subset))
                            layer.setSubsetString(subset)
                        if verbose_log:
                            feedback.pushDebugInfo('new source {}'.format(
                                layer.dataProvider().dataSourceUri()))

                    return conversion_results.layer_map[result_key]
            else:
                if not path.exists():
                    error = 'The referenced file {} does NOT exist!'.format(
                        str(path))
                else:
                    error = 'The referenced file exists, but could not open {} ({}) for conversion'.format(
                        source_uri, source['layerName'])

                if verbose_log:
                    feedback.reportError(error)
                    feedback.pushDebugInfo('Restoring stored URI')

                layer.setDataSource(uri, layer.name(), 'ogr', provider_options)
                if subset:
                    if verbose_log:
                        feedback.pushDebugInfo(
                            'Resetting subset string: {}'.format(subset))
                    layer.setSubsetString(subset)

                conversion_results.layer_map[result_key] = {'error': error}
                return conversion_results.layer_map[result_key]

        if verbose_log:
            feedback.pushDebugInfo('Source is valid, converting')

        options = QgsVectorFileWriter.SaveVectorOptions()

        options.layerName = layer_name_candidate
        options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer if pathlib.Path(
            dest_file_name).exists(
            ) else QgsVectorFileWriter.CreateOrOverwriteFile
        options.feedback = feedback

        error, error_message = QgsVectorFileWriter.writeAsVectorFormatV2(
            source_layer, dest_file_name, project.transformContext(), options)
        if error != QgsVectorFileWriter.NoError:
            if verbose_log:
                feedback.reportError('Failed: {}'.format(error_message))
                feedback.pushDebugInfo('Restoring stored URI')

            layer.setDataSource(uri, layer.name(), 'ogr', provider_options)
            if subset:
                if verbose_log:
                    feedback.pushDebugInfo(
                        'Resetting subset string: {}'.format(subset))
                layer.setSubsetString(subset)

            conversion_results.layer_map[result_key] = {'error': error_message}
            return conversion_results.layer_map[result_key]

        if verbose_log:
            feedback.pushDebugInfo('Success!')

        provider_options = QgsDataProvider.ProviderOptions()
        provider_options.transformContext = project.transformContext()
        subset = layer.subsetString()
        layer.setDataSource(
            QgsProviderRegistry.instance().encodeUri(
                'ogr', {
                    'path': dest_file_name,
                    'layerName': options.layerName
                }), layer.name(), 'ogr', provider_options)
        if subset:
            if verbose_log:
                feedback.pushDebugInfo(
                    'Resetting subset string: {}'.format(subset))
            layer.setSubsetString(subset)

        if verbose_log:
            feedback.pushDebugInfo('new source {}'.format(
                layer.dataProvider().dataSourceUri()))

        conversion_results.layer_map[result_key] = {
            'sourcePath': source['path'],
            'sourceLayer': source['layerName'],
            'destPath': dest_file_name,
            'destLayer': options.layerName
        }

        return conversion_results.layer_map[result_key]