Lightweight Python client for discovering and downloading OpenStreetMap extracts from Geofabrik.
Project description
Geofabrik Downloader
A small, strictly-typed Python client and CLI for discovering and downloading OpenStreetMap extracts from Geofabrik. One runtime dependency (httpx), MIT-licensed, and deliberately scoped to fetching — pair it with pyrosm, pyosmium, or geopandas to parse what you download.
Status: alpha (
0.1.x). Public API may change before1.0.
Why another one
Geofabrik publishes daily OSM extracts for every continent, country, and many sub-national regions. The existing Python options have problems:
pydriosmpulls inpandas,numpy,shapely,bs4,pyhelpers,pyrcs, and a PostgreSQL I/O layer just to download a file — and is GPLv3, which rules it out for many commercial codebases.osmnxtalks to Overpass, not Geofabrik.pyrosmparses.osm.pbffiles but expects you to source them yourself.
geofabrik-downloader does one thing well: list the catalogue and download files, with checksum verification, resumable transfers, and a typed surface.
Features
- Structured catalogue — region discovery via Geofabrik's
index-v1.json; no HTML scraping. - Browse & search —
list_regions,search_regions,children_of,get_region. - Local index cache — configurable TTL with an explicit
refresh_index()escape hatch. - All published formats —
.osm.pbf,.shp.zip,.gpkg.zip,.osm.bz2,.poly,.kml. - MD5 verification — verified against the published
.md5sidecar by default. - Resumable downloads — HTTP
Rangerequests with a progress-callback hook. - Spatial lookup — optional
find_by_point/find_by_bboxwhen the geometry-bearing index is loaded. - Shapefile layer extraction —
list_layersandextract_layerpull a single layer out of.shp.zipwithout shapely or geopandas. - Split-region handling —
composite_parts/download_parts(CLI:--parts) transparently fetch every child file when Geofabrik splits a region across siblings (e.g.us/california→norcal+socalforshp). - Full CLI —
geofabrik list | search | children | info | url | download | find-point | find-bbox | layers | extract | refresh, with Rich progress bars and a--jsonmode for scripting. - Stable script-friendly exit codes — distinct codes for region-not-found, format-unavailable, checksum-mismatch, etc.
py.typed, mypy-strict, noAnyin the public API.
Installation
pip install geofabrik-downloader # library only
pip install "geofabrik-downloader[cli]" # adds the geofabrik CLI (typer + rich)
Requires Python 3.10+.
Quick start — Python API
from geofabrik import Client
with Client() as client:
# Top-level continents
for region in client.list_regions(parent=None):
print(region.id, region.name)
# Inspect a region
turkey = client.get_region("turkey")
print(turkey.available_formats) # e.g. frozenset({'pbf', 'shp', 'poly', 'kml'})
# Download with MD5 verification (default)
result = client.download(turkey, format="pbf", dest="./data")
print(f"Saved {result.bytes_written} bytes to {result.path}")
Searching and walking the hierarchy
with Client() as client:
matches = client.search_regions("bavaria")
for region in client.children_of("germany"):
print(region.id)
Resumable downloads with progress
def on_progress(downloaded: int, total: int | None) -> None:
pct = f"{downloaded / total:.1%}" if total else f"{downloaded} B"
print(f"\r{pct}", end="")
with Client() as client:
client.download("monaco", format="pbf", dest="./data", progress=on_progress)
Interrupt and re-run the same command — the transfer resumes via HTTP Range.
Spatial lookup
Spatial helpers require the full geometry-bearing index (≈50 MB):
with Client(include_geometry=True) as client:
hits = client.find_by_point(lat=41.0, lon=29.0) # smallest containing region first
print(hits[0].id)
Split regions (e.g. California)
A handful of oversized regions are published only as multiple child files rather than a single download. The clearest example is us/california: the parent has pbf but its shp lives on two children, norcal and socal. To handle this transparently:
with Client() as client:
# Discover the parts first (returns [] for regions that aren't split):
parts = client.composite_parts("us/california", "shp")
print([r.id for r in parts]) # ['norcal', 'socal']
# Or just download them all — also works for un-split regions
# (returns a single-element list in that case):
for result in client.download_parts("us/california", "shp", dest="./data"):
print(result.path)
The CLI exposes the same via --parts:
geofabrik download us/california --format shp --parts -d ./data
If you call download (without --parts) on a split region/format combo, the resulting FormatNotAvailableError names the parts in its message so the next step is obvious.
Merging the two shapefiles is out of scope for this package (which deliberately doesn't depend on
geopandas/shapely). The shortest recipe isgpd.GeoDataFrame(pd.concat([gpd.read_file(p) for p in paths]))filtered to one layer, but a non-Python tool such asogr2ogr -update -append california.shp norcal_buildings.shpworks just as well.
Extracting a single shapefile layer
with Client() as client:
zip_path = client.download("monaco", format="shp", dest="./data").path
print(client.list_layers(zip_path)) # e.g. [roads, buildings, ...]
client.extract_layer(zip_path, "roads", "./out") # writes only roads.* files
Quick start — CLI
Install with the [cli] extras, then:
geofabrik list # continents
geofabrik list --parent europe # children of a region
geofabrik search bavaria
geofabrik children germany
geofabrik info turkey # available formats, size hints, parent
geofabrik url turkey --format pbf # print the download URL
geofabrik download turkey --format pbf -d ./data
geofabrik find-point 41.0 29.0
geofabrik find-bbox 28.5 40.8 29.5 41.3
geofabrik layers ./data/monaco-latest-free.shp.zip
geofabrik extract ./data/monaco-latest-free.shp.zip roads ./out
geofabrik refresh # force-refresh the cached index
Global flags: --cache-dir, --index-ttl, --timeout, --user-agent, --json, --quiet, --verbose.
Exit codes (stable contract for shell scripts):
| Code | Meaning |
|---|---|
| 0 | success |
| 1 | generic error |
| 2 | region not found |
| 3 | format not available for that region |
| 4 | checksum mismatch |
| 5 | shapefile layer not found |
| 6 | spatial command used without the geometry-bearing index |
Error handling
All package-specific exceptions derive from GeofabrikError:
from geofabrik import (
ChecksumMismatchError, FormatNotAvailableError, GeometryNotLoadedError,
IndexFetchError, LayerNotFoundError, RegionNotFoundError,
)
Configuration
Client(...) accepts:
cache_dir— where the index JSON and partial downloads live (default: platform cache dir).index_ttl_hours— how long the cached index is considered fresh (default: 24).timeout— per-request timeout in seconds (default: 30).user_agent— custom UA; please set this for non-trivial usage out of courtesy to Geofabrik.include_geometry— load the geometry-bearing index for spatial lookup (find_by_*).
What this package does not do
- Parse PBF or Shapefile content — use
pyrosm,pyosmium, orgeopandas. - Write to a database — bring your own
sqlalchemy/psycopg. - Query Overpass / Nominatim — use
osmnxoroverpy. - Download from BBBike or other OSM mirrors.
These are deliberate scope choices, not roadmap items.
Development
git clone https://github.com/uucokgis/Geofabrik-Downloader
cd Geofabrik-Downloader
python -m venv venv && source venv/bin/activate
pip install -e ".[cli,dev]"
pytest # unit tests (no network)
pytest -m network # integration tests against the real Geofabrik API
ruff check . && mypy
Tests live under tests/ and cover the cache, catalogue, client, downloader, extractor, the CLI, and an end-to-end integration suite. The network marker isolates tests that hit download.geofabrik.de.
Contributing
See IMPLEMENTATION.md for the technical design and open questions. Issues and PRs welcome.
License
MIT. OpenStreetMap data itself is © OpenStreetMap contributors, licensed under the ODbL by the OpenStreetMap Foundation.
Acknowledgements
Built on the public catalogue maintained by Geofabrik GmbH. Problem statement inspired by pydriosm. If you use OSM data at scale, please consider donating to OpenStreetMap.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file geofabrik_downloader-0.1.1.tar.gz.
File metadata
- Download URL: geofabrik_downloader-0.1.1.tar.gz
- Upload date:
- Size: 33.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3bf27cebc17b95af0828ca32091c433789733b776116095cdd26c0970af8aeb6
|
|
| MD5 |
50c6fdb38d1bcb265f0a9984a3df0b77
|
|
| BLAKE2b-256 |
661b4aa134966773a33e299ad27d5dad188c0d9e56dd1dbd91e24e0821c58434
|
Provenance
The following attestation bundles were made for geofabrik_downloader-0.1.1.tar.gz:
Publisher:
publish.yml on uucokgis/Geofabrik-Downloader
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
geofabrik_downloader-0.1.1.tar.gz -
Subject digest:
3bf27cebc17b95af0828ca32091c433789733b776116095cdd26c0970af8aeb6 - Sigstore transparency entry: 1629451004
- Sigstore integration time:
-
Permalink:
uucokgis/Geofabrik-Downloader@09af5889e993053a83fc1d09a19f5df0f4480962 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/uucokgis
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@09af5889e993053a83fc1d09a19f5df0f4480962 -
Trigger Event:
push
-
Statement type:
File details
Details for the file geofabrik_downloader-0.1.1-py3-none-any.whl.
File metadata
- Download URL: geofabrik_downloader-0.1.1-py3-none-any.whl
- Upload date:
- Size: 25.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6af19ec564c4fea5be14a427e842ecb561ef709da15ffddcb504c00e2adc0dc4
|
|
| MD5 |
091af38f0330cb471df300377b5342ad
|
|
| BLAKE2b-256 |
e2616ff7656fff87bb36ad379d9aa43fef0632e72ff35c0cd8d5cb7f1ab4cf04
|
Provenance
The following attestation bundles were made for geofabrik_downloader-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on uucokgis/Geofabrik-Downloader
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
geofabrik_downloader-0.1.1-py3-none-any.whl -
Subject digest:
6af19ec564c4fea5be14a427e842ecb561ef709da15ffddcb504c00e2adc0dc4 - Sigstore transparency entry: 1629451013
- Sigstore integration time:
-
Permalink:
uucokgis/Geofabrik-Downloader@09af5889e993053a83fc1d09a19f5df0f4480962 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/uucokgis
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@09af5889e993053a83fc1d09a19f5df0f4480962 -
Trigger Event:
push
-
Statement type: