Async alternatives to osmnx's IO-bound public API functions
Project description
osmnx-async
Async versions of osmnx's network-bound functions. Same names, same parameters, same return types — just add await.
Note: This is an independent community project and is not affiliated with or endorsed by the osmnx project or its maintainers.
Why?
osmnx makes synchronous HTTP requests to the Overpass and Nominatim APIs. If you're building an async application (FastAPI, aiohttp, Discord bots, data pipelines with asyncio.gather), those blocking calls stall your entire event loop.
osmnx-async replaces only the HTTP layer with httpx AsyncClient. All business logic — graph construction, simplification, GeoDataFrame creation — is delegated to osmnx itself. You get identical results, verified by integration tests that compare every node, edge, and attribute.
Installation
pip install osmnx-async
Requires Python 3.11+ and osmnx 2.x.
Quick start
import asyncio
import osmnx_async as ox
async def main():
# Exactly the same call you'd make with osmnx — just awaited
G = await ox.graph_from_place("Piedmont, CA, USA", network_type="drive")
print(f"{len(G)} nodes, {len(G.edges)} edges")
asyncio.run(main())
Migrating from osmnx
The function signatures are identical. Add await and swap the import:
# Before (sync)
import osmnx as ox
G = ox.graph_from_address("1600 Pennsylvania Ave, Washington DC", dist=500)
gdf = ox.features_from_place("Manhattan, NY", tags={"building": True})
point = ox.geocode("London, UK")
# After (async)
import osmnx_async as ox
G = await ox.graph_from_address("1600 Pennsylvania Ave, Washington DC", dist=500)
gdf = await ox.features_from_place("Manhattan, NY", tags={"building": True})
point = await ox.geocode("London, UK")
Module-level access works too:
from osmnx_async import graph, features, geocoder
G = await graph.graph_from_place("Piedmont, CA, USA")
gdf = await features.features_from_bbox(bbox, tags={"amenity": True})
point = await geocoder.geocode("Tokyo, Japan")
Settings
osmnx-async reads settings directly from osmnx.settings. Configure them the same way you always have:
import osmnx as ox
ox.settings.use_cache = True
ox.settings.cache_folder = "./my_cache"
ox.settings.overpass_rate_limit = True
ox.settings.requests_timeout = 300
The cache is shared — a response cached by a sync osmnx call is reused by osmnx-async, and vice versa.
Concurrent requests
The main reason to go async. Fetch multiple graphs in parallel instead of sequentially:
import asyncio
import osmnx_async as ox
async def main():
cities = ["Piedmont, CA, USA", "Berkeley, CA, USA", "Emeryville, CA, USA"]
graphs = await asyncio.gather(
*(ox.graph_from_place(c, network_type="drive") for c in cities)
)
for city, G in zip(cities, graphs):
print(f"{city}: {len(G)} nodes")
asyncio.run(main())
Note: Overpass and Nominatim enforce rate limits. osmnx-async respects these automatically (Nominatim: 1 req/sec per hostname, Overpass: server-side slot management). Concurrent tasks will wait as needed.
Available functions
Every osmnx function that makes HTTP requests has an async equivalent:
| Module | Function | What it does |
|---|---|---|
graph |
graph_from_bbox |
Graph within bounding box |
graph |
graph_from_point |
Graph within distance of point |
graph |
graph_from_address |
Graph within distance of address |
graph |
graph_from_place |
Graph within place boundary |
graph |
graph_from_polygon |
Graph within polygon |
features |
features_from_bbox |
OSM features within bounding box |
features |
features_from_point |
OSM features within distance of point |
features |
features_from_address |
OSM features within distance of address |
features |
features_from_place |
OSM features within place boundary |
features |
features_from_polygon |
OSM features within polygon |
geocoder |
geocode |
Place name to (lat, lon) |
geocoder |
geocode_to_gdf |
Place name to GeoDataFrame |
elevation |
add_node_elevations_google |
Add elevation data to graph nodes |
Functions that don't make network requests (plotting, stats, simplification, IO, routing, etc.) are pure computation and don't need async variants. Use them directly from osmnx as usual.
Compatibility
osmnx-async validates at import time that the osmnx internals it depends on are present and have the expected signatures. If osmnx releases a breaking change, you'll get a clear error at import osmnx_async rather than a cryptic failure deep in a call stack:
OsmnxCompatibilityError: osmnx-async depends on osmnx internals that are
missing in the installed version. Missing: osmnx.graph._create_graph
Supported: osmnx >= 2.0, < 3.0.
Development
git clone https://github.com/cmcconomyfwig/osmnx-async.git
cd osmnx-async
uv sync
# Unit tests (mocked, fast)
make test
# Integration tests (real API calls, slower)
make test-integration
# Build (syncs version from installed osmnx, then builds wheel)
make build
License
MIT
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 osmnx_async-2.1.0.post1.tar.gz.
File metadata
- Download URL: osmnx_async-2.1.0.post1.tar.gz
- Upload date:
- Size: 79.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7de6b9d07f6daec045ebc03d3eaeaa100fb5a2cbde080d315d1391b5b3a94a77
|
|
| MD5 |
4f3376cddf90f7a12ecf338b88cb9c9e
|
|
| BLAKE2b-256 |
8e48a0634f17c7610b02a1fdd30a8003d0352981b4a30fcdc104b3003f9a0082
|
Provenance
The following attestation bundles were made for osmnx_async-2.1.0.post1.tar.gz:
Publisher:
publish.yml on cmcconomyfwig/osmnx-async
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
osmnx_async-2.1.0.post1.tar.gz -
Subject digest:
7de6b9d07f6daec045ebc03d3eaeaa100fb5a2cbde080d315d1391b5b3a94a77 - Sigstore transparency entry: 957093072
- Sigstore integration time:
-
Permalink:
cmcconomyfwig/osmnx-async@e23d59c7b850663ae6257b9dc5a74f9c09d6d0f0 -
Branch / Tag:
refs/tags/v2.1.0.post1 - Owner: https://github.com/cmcconomyfwig
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e23d59c7b850663ae6257b9dc5a74f9c09d6d0f0 -
Trigger Event:
release
-
Statement type:
File details
Details for the file osmnx_async-2.1.0.post1-py3-none-any.whl.
File metadata
- Download URL: osmnx_async-2.1.0.post1-py3-none-any.whl
- Upload date:
- Size: 21.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f34151b9343f5effd0ebbe941783e77ecfee61de3de60ad022c2e2f201916b69
|
|
| MD5 |
b4b941981f6bb1a705390367f43e2153
|
|
| BLAKE2b-256 |
f48ceca554fcc01b78a18c655f6149b84e7ec0efa8e23db6421333ac4f667db5
|
Provenance
The following attestation bundles were made for osmnx_async-2.1.0.post1-py3-none-any.whl:
Publisher:
publish.yml on cmcconomyfwig/osmnx-async
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
osmnx_async-2.1.0.post1-py3-none-any.whl -
Subject digest:
f34151b9343f5effd0ebbe941783e77ecfee61de3de60ad022c2e2f201916b69 - Sigstore transparency entry: 957093125
- Sigstore integration time:
-
Permalink:
cmcconomyfwig/osmnx-async@e23d59c7b850663ae6257b9dc5a74f9c09d6d0f0 -
Branch / Tag:
refs/tags/v2.1.0.post1 - Owner: https://github.com/cmcconomyfwig
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e23d59c7b850663ae6257b9dc5a74f9c09d6d0f0 -
Trigger Event:
release
-
Statement type: