Skip to main content

geopackage-toolkit

CI Docs License: MIT

Python toolkit for GeoPackage spatial data. Validate, query, and operate on spatial data without PostGIS or ArcGIS.

Zero compiled dependencies. Uses SpatiaLite (embedded in SQLite) for all spatial operations. One file format (.gpkg), one dependency chain, clean Python API.

from geopkgtoolkit import connect, validate_layers, count_in_zones

# Validate geometry health
report = validate_layers("data.gpkg", expected_srid=4326)
print(report.summary())

# Count buildings per administrative zone
con = connect("data.gpkg")
counts = count_in_zones(con, "buildings", "admin3")
for zone_id, count in counts[:5]:
    print(f"Zone {zone_id}: {count} buildings")

Why

GeoPackage is the OGC standard that replaces Shapefile. It's SQLite-based, supports vector + raster + tiles, and works everywhere. But the tooling around it is fractured:

  • ogr2ogr works but isn't Pythonic
  • GeoPandas adds heavy compiled dependencies
  • SpatiaLite has Windows quirks nobody documents
  • No single package covers validate-query-convert-publish

This toolkit fills that gap. Local-first, no server required.

Installation

pip install geopackage-toolkit

Prerequisites

SpatiaLite must be installed on your system:

OS Install
Windows Download from gaia-gis.it and set SPATIALITE_DIR env var
Ubuntu/Debian sudo apt install libspatialite-dev
macOS brew install libspatialite
Conda conda install -c conda-forge libspatialite

CLI

# Validate geometry health
geopkg validate data.gpkg --srid 4326

# Count features per zone
geopkg count data.gpkg --features buildings --zones admin3

# Show layer info
geopkg info data.gpkg

# Buffer features (output saved as new layer in same GeoPackage)
geopkg buffer data.gpkg --layer buildings --distance 100 --output buffered_buildings

# Clip a layer to a boundary
geopkg clip data.gpkg --source buildings --clip district_boundary --output clipped_buildings

# Spatial intersection of two layers
geopkg intersect data.gpkg --layer-a buildings --layer-b flood_zones --output buildings_in_flood

# Export a layer to GeoJSON (pure Python, no extra dependencies)
geopkg export data.gpkg --layer buildings --format geojson --output buildings.geojson

# Export a layer to Shapefile (requires: pip install geopackage-toolkit[convert])
geopkg export data.gpkg --layer buildings --format shapefile --output buildings.shp

# Import GeoJSON into a GeoPackage (creates the file if missing)
geopkg import buildings.geojson --output new_data.gpkg --layer buildings

# Import a Shapefile into a GeoPackage
geopkg import buildings.shp --output new_data.gpkg --layer buildings

Python API

Validate

from geopkgtoolkit import validate_layers, validate_layer

# Validate all layers
report = validate_layers("data.gpkg", expected_srid=4326)
print(report.summary())
# GeoPackage: data.gpkg
# 9 layers, 685,968 features, 0 warnings
#   OSM_Buildings: 515,013 features, SRID=4326, OK
#   lbn_adm3: 1,627 features, SRID=4326, OK
#   ...

assert report.is_valid  # True if no warnings

# Validate a single layer
con = validate_layer(con, "buildings", expected_srid=4326)

Checks: null geometries, empty geometries, invalid geometries (self-intersections), SRID mismatches, bounding box sanity.

Query

from geopkgtoolkit import connect, count_in_zones, bbox_filter

con = connect("data.gpkg")

# Count features per zone (rtree-accelerated)
counts = count_in_zones(con, "buildings", "admin3")
# Returns: [(zone_fid, count), ...]

# Bounding box filter (rtree-accelerated)
fids = bbox_filter(con, "buildings", (35.4, 33.8, 35.6, 33.9))
# Returns: [fid, ...]

# Point-in-polygon classification
from geopkgtoolkit import points_in_polygons
result = points_in_polygons(con, "pois", "districts")
# Returns: [(point_fid, polygon_fid_or_None), ...]

Spatial Operations

from geopkgtoolkit import connect, buffer, clip, intersect

con = connect("data.gpkg")

# Buffer features by a distance (CRS units)
buffered = buffer(con, "buildings", distance=100, output_table="buffered_buildings")
# Creates new layer with buffered polygons

# Clip features to a boundary
clipped = clip(con, "buildings", "district_boundary", output_table="clipped_buildings")
# Creates new layer with features clipped to polygon boundary

# Spatial intersection of two layers
result = intersect(con, "buildings", "flood_zones", output_table="buildings_in_flood")
# Creates new layer with the intersection of two layers

All operations write results back to the same GeoPackage file. Attributes from both layers are preserved in intersection.

Format Conversion

from geopkgtoolkit import connect, export_geojson, export_shapefile, import_geojson, import_shapefile

con = connect("data.gpkg")

# Export to GeoJSON (pure Python, zero extra dependencies)
export_geojson(con, "buildings", "buildings.geojson")

# Export to Shapefile (requires: pip install geopackage-toolkit[convert])
export_shapefile(con, "buildings", "buildings.shp")
con.close()

# Import GeoJSON (creates the GeoPackage if it doesn't exist)
import_geojson("new_data.gpkg", "input.geojson", "buildings")

# Import Shapefile
import_shapefile("new_data.gpkg", "input.shp", "buildings")

GeoJSON export/import is pure Python. Shapefile support requires the optional pyshp dependency: pip install geopackage-toolkit[convert].

Connect

from geopkgtoolkit import connect

con = connect("data.gpkg")  # Auto-loads SpatiaLite
layers = con.execute("SELECT table_name FROM gpkg_geometry_columns").fetchall()
con.close()

How It Works

All spatial operations use SpatiaLite (embedded spatial SQL extension for SQLite) with GeoPackage's native rtree tables for spatial indexing. This means:

  • No server process (unlike PostGIS)
  • No compiled Python bindings (unlike GeoPandas/GDAL wheels)
  • Single .gpkg file per dataset
  • Works on Windows, Linux, macOS

Performance

Operation Method 500k features x 1k zones
count_in_zones rtree bbox + ST_Contains ~8 seconds
count_in_zones (no index) ST_Contains only >10 minutes
bbox_filter rtree lookup <1 second

The toolkit auto-creates rtree indexes when missing. First run builds the index, subsequent runs use it.

Roadmap

  • v0.1.0: Validate + Query modules
  • v0.2.0: Spatial operations (buffer, clip, intersect) with CLI commands
  • v0.3.0: Format conversion (Shapefile, GeoJSON, FlatGeobuf to/from GeoPackage)
  • v0.4.0: Config-driven batch pipeline
  • v0.5.0: Vector tile generation for web publishing
  • v1.0.0: Full toolkit with visualization and schema extraction

Contributing

Contributions welcome. Please open an issue first to discuss what you'd like to change.

License

MIT

Acknowledgments

Built on top of SpatiaLite by Alessandro Furieri and the GeoPackage OGC standard.

Release files for geopackage-toolkit 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for geopackage-toolkit 0.3.0
File Size Uploaded
geopackage_toolkit-0.3.0.tar.gz 45.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for geopackage-toolkit 0.3.0
File Interpreter ABI Platform
geopackage_toolkit-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 70.1 kB

Release files / geopackage_toolkit-0.3.0.tar.gz

Download URL geopackage_toolkit-0.3.0.tar.gz
Size 45.1 kB
Tags Source
SHA-256 checksum
How to use checksums
f500e1c3e140aff07e40d9ded98491d5b3bd37f5fb21bfa4b86d3ddad57a3a27
BLAKE2b-256 checksum
How to use checksums
cc1d4e843bbbe37303a74a1c647f9005cf5d6b31236f14dd86245dd64ee15b80
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.0

Release files / geopackage_toolkit-0.3.0-py3-none-any.whl

Download URL geopackage_toolkit-0.3.0-py3-none-any.whl
Size 25.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a51214a9a056bd63698a531ff4eeaf96759f240053af2696467d38f7169477b4
BLAKE2b-256 checksum
How to use checksums
dfc584b731b3723906fac0aadfd1f54e6c07687ae81133c70efc096ac3f1c16a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.0

Release history Release notifications | RSS feed

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

This release

0.3.0 This release

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page