I want to create empty GeoPackage layers with a defined schema. This seems to just work with Fiona regardless of whether I have spatial or non-spatial layers:
def create_blank_gpkg_layer( gpkg: Path, layer_name: str, crs: dict, schema: dict ) -> dict: """ Thin wrapper around fiona.open to create an empty layer in a geopackage If the geopackage doesn't exist it is created. Any existing geopackage or layer that shares the same names are overwritten """ gpkg.parent.mkdir(exist_ok=True, parents=True) with fiona.open( gpkg, "w", driver="GPKG", crs=crs, layer=layer_name, schema=schema, overwrite=True, ) as new_layer: meta = new_layer.meta print(f"{layer_name} created in {gpkg}") return meta wgs_crs = from_epsg(4326) poly_schema = { "properties": OrderedDict([("name":"str"),("code":"int")]), "geometry": "Polygon" } not_spatial_schema = {"properties": OrderedDict([("name":"str"),("code":"int")])} create_blank_gpkg_layer(gpkg, layer_name=poly, crs=crs, schema=poly_schema) create_blank_gpkg_layer(gpkg, layer_name=not_spatial, crs=crs, schema=not_spatial_schema) This is fine, but I'd rather not have fiona as a dependency if the capability is already within QGIS - which is where the GeoPackages will end up, and I will have seperate code to configure symbology etc.
So I'd like to do the same using the PyQGIS QgsVectorFileWriter or whatever is most appropriate.
I've managed to make a workaround that creates a memory layer and then writes it, but I feel like there is probably a more 'idiomatic' way of solving this, as I then have to get the layer I've created in the GeoPackage (the one I actually want) and add it to the map.
# Layers that have a geometry foo_layer = QgsVectorLayer("Point?crs=epsg:4326&field=name:string", "foo layer", "memory") params={'INPUT': foo_layer, 'OPTIONS':'-update -nln foo','OUTPUT': '/tmp/temp_gpkg.gpkg'} processing.run("gdal:convertformat", params) # Layers with no geometry bar_layer = QgsVectorLayer('None', 'bar', 'memory') bar_layer.startEditing() bar_layer.addAttribute(QgsField('name',QVariant.String)) bar_layer.commitChanges() params={'INPUT': bar_layer,'OPTIONS':'-update -nln bar','OUTPUT': '/tmp/temp_gpkg.gpkg'} processing.run("gdal:convertformat", params)
ogrinfo -sql "create table foo (attr1 text, attr2 int)" test.gpkg. But if your aim is to create a table with a geometry column then it gets more complicated.