osmfeatures 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- osmfeatures-0.1.0/.github/copilot-instructions.md +11 -0
- osmfeatures-0.1.0/.github/instructions/osmgeojson-python-conventions.instructions.md +15 -0
- osmfeatures-0.1.0/.gitignore +16 -0
- osmfeatures-0.1.0/LICENSE +21 -0
- osmfeatures-0.1.0/Makefile +15 -0
- osmfeatures-0.1.0/PKG-INFO +253 -0
- osmfeatures-0.1.0/README.md +213 -0
- osmfeatures-0.1.0/pyproject.toml +64 -0
- osmfeatures-0.1.0/src/osmfeatures/__init__.py +102 -0
- osmfeatures-0.1.0/src/osmfeatures/_http.py +136 -0
- osmfeatures-0.1.0/src/osmfeatures/_pagination.py +112 -0
- osmfeatures-0.1.0/src/osmfeatures/async_client.py +297 -0
- osmfeatures-0.1.0/src/osmfeatures/chunking.py +117 -0
- osmfeatures-0.1.0/src/osmfeatures/cli.py +310 -0
- osmfeatures-0.1.0/src/osmfeatures/client.py +374 -0
- osmfeatures-0.1.0/src/osmfeatures/convenience.py +424 -0
- osmfeatures-0.1.0/src/osmfeatures/models.py +197 -0
- osmfeatures-0.1.0/src/osmfeatures/output.py +124 -0
- osmfeatures-0.1.0/src/osmfeatures/py.typed +0 -0
- osmfeatures-0.1.0/src/osmfeatures/retry.py +144 -0
- osmfeatures-0.1.0/tests/.env.example +2 -0
- osmfeatures-0.1.0/tests/README.md +50 -0
- osmfeatures-0.1.0/tests/__init__.py +0 -0
- osmfeatures-0.1.0/tests/conftest.py +100 -0
- osmfeatures-0.1.0/tests/example_apps/__init__.py +0 -0
- osmfeatures-0.1.0/tests/example_apps/conftest.py +105 -0
- osmfeatures-0.1.0/tests/example_apps/graph_utils.py +75 -0
- osmfeatures-0.1.0/tests/example_apps/test_bike_path_dijkstra_liljeholmen_to_djurgarden.py +160 -0
- osmfeatures-0.1.0/tests/example_apps/test_city_cycling_infrastructure.py +81 -0
- osmfeatures-0.1.0/tests/example_apps/test_cycling_trails.py +58 -0
- osmfeatures-0.1.0/tests/example_apps/test_geometry_filters.py +116 -0
- osmfeatures-0.1.0/tests/example_apps/test_lakeside_ice_cream_hunt.py +155 -0
- osmfeatures-0.1.0/tests/example_apps/test_park_bench_finder.py +38 -0
- osmfeatures-0.1.0/tests/example_apps/test_park_explorer.py +64 -0
- osmfeatures-0.1.0/tests/example_apps/test_pedestrian_shortest_path.py +123 -0
- osmfeatures-0.1.0/tests/example_apps/test_pedestrian_wavefront_bfs.py +156 -0
- osmfeatures-0.1.0/tests/example_apps/test_restaurant_guide.py +55 -0
- osmfeatures-0.1.0/tests/test_async_client.py +440 -0
- osmfeatures-0.1.0/tests/test_chunking.py +86 -0
- osmfeatures-0.1.0/tests/test_cli.py +231 -0
- osmfeatures-0.1.0/tests/test_client.py +306 -0
- osmfeatures-0.1.0/tests/test_output.py +74 -0
- osmfeatures-0.1.0/tests/test_pagination.py +149 -0
- osmfeatures-0.1.0/tests/test_retry.py +105 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Copilot Instructions for osmgeojson-python
|
|
2
|
+
|
|
3
|
+
Always-on baseline for this repository.
|
|
4
|
+
|
|
5
|
+
MapLark is a self-hosted GeoJSON API over OpenStreetMap data, backed by PostGIS and served via FastAPI.
|
|
6
|
+
|
|
7
|
+
- Keep changes minimal and backward compatible unless a task explicitly asks for breaking changes.
|
|
8
|
+
- Prefer strong typing and mypy-compatible changes.
|
|
9
|
+
- Keep sync and async client behavior aligned for equivalent features.
|
|
10
|
+
- Prefer deterministic tests with mocked HTTP over live network calls.
|
|
11
|
+
- Treat `.github/instructions/*.instructions.md` as the source of detailed, file-specific rules.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Use when editing Python code in osmgeojson (SDK, tests, or examples). Prefer strict typing, sync/async parity, and deterministic tests unless the task requires an exception."
|
|
3
|
+
name: "OSMGeoJSON Python Conventions"
|
|
4
|
+
applyTo: "**/*.py"
|
|
5
|
+
---
|
|
6
|
+
# OSMGeoJSON Python Conventions
|
|
7
|
+
|
|
8
|
+
- Prefer complete type hints that remain compatible with strict mypy checks.
|
|
9
|
+
- Prefer preserving public API compatibility unless the task explicitly requests a breaking change.
|
|
10
|
+
- When adding or changing request parameters in the sync client, prefer mirroring the behavior in the async client unless there is a documented reason not to.
|
|
11
|
+
- Prefer routing HTTP retries and rate-limit handling through shared retry/http helpers instead of duplicating retry logic in client methods.
|
|
12
|
+
- For pagination or chunking changes, preserve deduplication-by-id behavior and existing guardrails against stale offsets.
|
|
13
|
+
- For tests that exercise HTTP flows, prefer mocked HTTP requests (for example with `responses`) and avoid live network calls.
|
|
14
|
+
- Add or update tests for behavioral changes, including both success and error paths when practical.
|
|
15
|
+
- Keep docstrings user-focused: include parameter semantics and API-specific constraints rather than generic restatements.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MapLark
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
SHELL := /bin/bash
|
|
2
|
+
|
|
3
|
+
VENV_DIR := $(CURDIR)/.venv
|
|
4
|
+
VENV_PY := $(VENV_DIR)/bin/python3
|
|
5
|
+
VENV_PIP := $(VENV_DIR)/bin/pip
|
|
6
|
+
setup:
|
|
7
|
+
python3 -m venv $(VENV_DIR)
|
|
8
|
+
source $(VENV_DIR)/bin/activate
|
|
9
|
+
$(VENV_PIP) install -e ".[all,test]"
|
|
10
|
+
|
|
11
|
+
test: setup
|
|
12
|
+
$(VENV_PY) -m pytest tests/ -v
|
|
13
|
+
|
|
14
|
+
clean:
|
|
15
|
+
rm -rf $(VENV_DIR)
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: osmfeatures
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official client for the MapLark OSM Features API (GeoJSON, FlatGeobuf, GeoParquet, CSV)
|
|
5
|
+
Project-URL: Homepage, https://maplark.com
|
|
6
|
+
Project-URL: Repository, https://github.com/MapLark/osmfeatures-python
|
|
7
|
+
License: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: flatgeobuf,geojson,geoparquet,geospatial,maplark,maps,openstreetmap,osm,overpass
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Requires-Dist: click>=8.1
|
|
21
|
+
Requires-Dist: geojson>=3.0
|
|
22
|
+
Requires-Dist: httpx>=0.27
|
|
23
|
+
Requires-Dist: requests>=2.28
|
|
24
|
+
Provides-Extra: all
|
|
25
|
+
Requires-Dist: geopandas>=0.14; extra == 'all'
|
|
26
|
+
Requires-Dist: pandas>=2.0; extra == 'all'
|
|
27
|
+
Requires-Dist: shapely>=2.0; extra == 'all'
|
|
28
|
+
Provides-Extra: geo
|
|
29
|
+
Requires-Dist: geopandas>=0.14; extra == 'geo'
|
|
30
|
+
Requires-Dist: pandas>=2.0; extra == 'geo'
|
|
31
|
+
Requires-Dist: shapely>=2.0; extra == 'geo'
|
|
32
|
+
Provides-Extra: test
|
|
33
|
+
Requires-Dist: haversine>=2.8; extra == 'test'
|
|
34
|
+
Requires-Dist: networkx>=3.0; extra == 'test'
|
|
35
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'test'
|
|
36
|
+
Requires-Dist: pytest>=7.0; extra == 'test'
|
|
37
|
+
Requires-Dist: python-dotenv>=1.0; extra == 'test'
|
|
38
|
+
Requires-Dist: responses>=0.25; extra == 'test'
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
# MapLark OSM Features API
|
|
42
|
+
|
|
43
|
+
Query OpenStreetMap features such as buildings, streets, and Points of Interest easily. Search for OSM features by bounding box, tags, and geometry shape and get GeoJSON back within less than 250ms (dependent on query size). No converting between formats manually. The API keeps OpenStreetMap semantics intact, like tags and ways, and returns GeoJSON Features you can feed straight into Leaflet, MapLibre, OpenLayers, or any geospatial toolchain. It is backed by postgis with tiered API keys and rate limiting to keep noisy neighbours out to give you predictable latency for real traffic. It also has self-host path for those willing to host complex infrastructure themselves.
|
|
44
|
+
|
|
45
|
+
The translation layer is very simple:
|
|
46
|
+
|
|
47
|
+
- `node` - GeoJSON Point
|
|
48
|
+
- `way` - LineString or Polygon
|
|
49
|
+
- `relation` - MultiPolygon or grouped geometries
|
|
50
|
+
|
|
51
|
+
You filter with the same tags mappers already use (`amenity=cafe`, `building=yes`, and so on). Knowledge from OSM, Overpass, and tagging docs transfers immediately.
|
|
52
|
+
|
|
53
|
+
To narrow down between "open ways" and "closed ways", use the `shape` parameter:
|
|
54
|
+
|
|
55
|
+
- `shape=line` - open ways (roads, paths, rivers) or line-shaped relations (routes, boundaries)
|
|
56
|
+
- `shape=polygon` - closed ways (buildings, parks) or multipolygon relations.
|
|
57
|
+
- `shape=all` - both shapes (default when shape is omitted).
|
|
58
|
+
|
|
59
|
+
For example, to get all buildings in an area:
|
|
60
|
+
|
|
61
|
+
`type=way & tags=building`
|
|
62
|
+
|
|
63
|
+
This is the equivalent of the Overpass query `way[building]`.
|
|
64
|
+
|
|
65
|
+
Read the full API reference here [https://maplark.com/developer](https://maplark.com/developer).
|
|
66
|
+
|
|
67
|
+
## Python SDK
|
|
68
|
+
|
|
69
|
+
This client library comes with auto-pagination, bbox tiling (enables larger bbox queries), retry/backoff, pandas/geopandas output, async support, and convenience methods to get common OSM data such as buildings, amenities, bike roads, etc.
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
pip install osmfeatures
|
|
73
|
+
pip install "osmfeatures[geo]" # pandas / geopandas / shapely support
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Official client for the MapLark OSM Features API (GeoJSON, FlatGeobuf, GeoParquet, CSV).
|
|
77
|
+
The SDK talks to `api.maplark.com` by default.
|
|
78
|
+
|
|
79
|
+
## Quick start
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from osmfeatures import OSMFeaturesClient
|
|
83
|
+
|
|
84
|
+
with OSMFeaturesClient(api_key="sk-...") as client:
|
|
85
|
+
fc = client.query(bbox="18.06,59.32,18.09,59.34", tags=["building"])
|
|
86
|
+
print(len(fc.features), "buildings found")
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
## Basic API usage
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
### 1) Create a client
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from osmfeatures import OSMFeaturesClient
|
|
99
|
+
|
|
100
|
+
client = OSMFeaturesClient(api_key="sk-...")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
You can use the client directly and close it when done, or use a context manager:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from osmfeatures import OSMFeaturesClient
|
|
107
|
+
|
|
108
|
+
with OSMFeaturesClient(api_key="sk-...") as client:
|
|
109
|
+
...
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
### 2) Query OSM features
|
|
115
|
+
|
|
116
|
+
`query()` fetches a single page:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
fc = client.query(
|
|
120
|
+
bbox="18.063,59.322,18.082,59.332",
|
|
121
|
+
type="way",
|
|
122
|
+
shape="line",
|
|
123
|
+
tags=["highway=cycleway"],
|
|
124
|
+
limit=500,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
for feature in fc.features:
|
|
128
|
+
print(feature["id"], feature["geometry"]["type"], feature.tags)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Common filters:
|
|
132
|
+
|
|
133
|
+
- `bbox="min_lon,min_lat,max_lon,max_lat"`
|
|
134
|
+
- `around="lon,lat,radius_m"`
|
|
135
|
+
- `tags=["amenity=restaurant"]` (AND)
|
|
136
|
+
- `or_tags=["bicycle=yes", "bicycle=designated"]` (OR)
|
|
137
|
+
- `not_tags=["access=private"]` (exclude)
|
|
138
|
+
- `type="node" | "way" | "relation"`
|
|
139
|
+
- `shape="polygon" | "line" | "all"` (omit = both shapes; `all` also means both)
|
|
140
|
+
- `cursor` (pagination; use SDK `meta.next_cursor` from previous page, sourced from `X-Next-Cursor`)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
### 3) Auto-pagination and bbox tiling
|
|
145
|
+
|
|
146
|
+
Use `query_all()` to fetch all pages and deduplicate by OSM feature id. By default it splits the bbox into 2 tiles (power of 2) so large areas use more requests; pass `bbox_tiles=1` to disable, or raise it (`4`, `8`, …) for bigger areas:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
all_restaurants = client.query_all(
|
|
150
|
+
bbox="18.063,59.322,18.082,59.332",
|
|
151
|
+
tags="amenity=restaurant",
|
|
152
|
+
limit_per_page=1000, # page size per HTTP request
|
|
153
|
+
max_features=55_000, # total cap; pass None for no cap
|
|
154
|
+
bbox_tiles=2, # default
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
print(all_restaurants.meta.returned)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
### 4) Async client
|
|
163
|
+
|
|
164
|
+
Async methods mirror the sync API (`query_async`, `query_all_async`):
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
import asyncio
|
|
168
|
+
from osmfeatures import AsyncOSMFeaturesClient
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
async def main() -> None:
|
|
172
|
+
async with AsyncOSMFeaturesClient(api_key="sk-...") as client:
|
|
173
|
+
fc = await client.query_async(
|
|
174
|
+
bbox="18.06,59.32,18.09,59.34",
|
|
175
|
+
tags=["building"],
|
|
176
|
+
)
|
|
177
|
+
print(len(fc.features))
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
asyncio.run(main())
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
### 5) Convenience helpers
|
|
186
|
+
|
|
187
|
+
For common datasets, use convenience methods built on top of `query_all()`:
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
from osmfeatures import OSMFeaturesClient, get_buildings, get_restaurants
|
|
191
|
+
|
|
192
|
+
with OSMFeaturesClient(api_key="sk-...") as client:
|
|
193
|
+
buildings = get_buildings(client, bbox="18.063,59.322,18.082,59.332")
|
|
194
|
+
restaurants = get_restaurants(client, bbox="18.063,59.322,18.082,59.332")
|
|
195
|
+
print(len(buildings.features), len(restaurants.features))
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
### 6) Cost and usage
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
estimate = client.estimate_cost(
|
|
204
|
+
bbox="18.063,59.322,18.082,59.332",
|
|
205
|
+
tags=["building"],
|
|
206
|
+
)
|
|
207
|
+
print("estimated credits:", estimate.estimated_credits)
|
|
208
|
+
|
|
209
|
+
usage = client.usage()
|
|
210
|
+
print("Usage:", usage)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
### 7) CLI usage
|
|
216
|
+
|
|
217
|
+
If the package is installed, the CLI is available as `osmfeatures`:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
export MAPLARK_API_KEY="sk-..."
|
|
221
|
+
osmfeatures query --bbox "18.063,59.322,18.082,59.332" --tags building --type way
|
|
222
|
+
osmfeatures query --bbox "18.063,59.322,18.082,59.332" --tags building --all-pages --bbox-tiles 4
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
## Example apps
|
|
228
|
+
|
|
229
|
+
The repository includes runnable example-app tests in `tests/example_apps/` showing end-to-end usage patterns against real OSM data.
|
|
230
|
+
|
|
231
|
+
- `test_restaurant_guide.py`: restaurant discovery list with names/cuisines and map coordinates.
|
|
232
|
+
- `test_park_bench_finder.py`: bench finder for park maps (`amenity=bench`).
|
|
233
|
+
- `test_park_explorer.py`: park browser with polygon boundaries, centroids, and area estimates.
|
|
234
|
+
- `test_cycling_trails.py`: unpaved cycling trail layer for MTB/gravel planning.
|
|
235
|
+
- `test_city_cycling_infrastructure.py`: city cycling overlay combining cycleways and bike lanes.
|
|
236
|
+
- `test_lakeside_ice_cream_hunt.py`: nearest ice cream shops to waterfront edges.
|
|
237
|
+
- `test_pedestrian_shortest_path.py`: shortest walking route via graph + Dijkstra.
|
|
238
|
+
- `test_pedestrian_wavefront_bfs.py`: hop-based accessibility rings via BFS.
|
|
239
|
+
- `test_bike_path_dijkstra_liljeholmen_to_djurgarden.py`: tiled corridor bike routing from Liljeholmen to Djurgarden.
|
|
240
|
+
- `test_geometry_filters.py`: zoom + area/length filters for large buildings and long roads.
|
|
241
|
+
|
|
242
|
+
Run all example apps:
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
pytest tests/example_apps -v
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Run one example app:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
pytest tests/example_apps/test_restaurant_guide.py -v
|
|
252
|
+
```
|
|
253
|
+
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# MapLark OSM Features API
|
|
2
|
+
|
|
3
|
+
Query OpenStreetMap features such as buildings, streets, and Points of Interest easily. Search for OSM features by bounding box, tags, and geometry shape and get GeoJSON back within less than 250ms (dependent on query size). No converting between formats manually. The API keeps OpenStreetMap semantics intact, like tags and ways, and returns GeoJSON Features you can feed straight into Leaflet, MapLibre, OpenLayers, or any geospatial toolchain. It is backed by postgis with tiered API keys and rate limiting to keep noisy neighbours out to give you predictable latency for real traffic. It also has self-host path for those willing to host complex infrastructure themselves.
|
|
4
|
+
|
|
5
|
+
The translation layer is very simple:
|
|
6
|
+
|
|
7
|
+
- `node` - GeoJSON Point
|
|
8
|
+
- `way` - LineString or Polygon
|
|
9
|
+
- `relation` - MultiPolygon or grouped geometries
|
|
10
|
+
|
|
11
|
+
You filter with the same tags mappers already use (`amenity=cafe`, `building=yes`, and so on). Knowledge from OSM, Overpass, and tagging docs transfers immediately.
|
|
12
|
+
|
|
13
|
+
To narrow down between "open ways" and "closed ways", use the `shape` parameter:
|
|
14
|
+
|
|
15
|
+
- `shape=line` - open ways (roads, paths, rivers) or line-shaped relations (routes, boundaries)
|
|
16
|
+
- `shape=polygon` - closed ways (buildings, parks) or multipolygon relations.
|
|
17
|
+
- `shape=all` - both shapes (default when shape is omitted).
|
|
18
|
+
|
|
19
|
+
For example, to get all buildings in an area:
|
|
20
|
+
|
|
21
|
+
`type=way & tags=building`
|
|
22
|
+
|
|
23
|
+
This is the equivalent of the Overpass query `way[building]`.
|
|
24
|
+
|
|
25
|
+
Read the full API reference here [https://maplark.com/developer](https://maplark.com/developer).
|
|
26
|
+
|
|
27
|
+
## Python SDK
|
|
28
|
+
|
|
29
|
+
This client library comes with auto-pagination, bbox tiling (enables larger bbox queries), retry/backoff, pandas/geopandas output, async support, and convenience methods to get common OSM data such as buildings, amenities, bike roads, etc.
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
pip install osmfeatures
|
|
33
|
+
pip install "osmfeatures[geo]" # pandas / geopandas / shapely support
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Official client for the MapLark OSM Features API (GeoJSON, FlatGeobuf, GeoParquet, CSV).
|
|
37
|
+
The SDK talks to `api.maplark.com` by default.
|
|
38
|
+
|
|
39
|
+
## Quick start
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from osmfeatures import OSMFeaturesClient
|
|
43
|
+
|
|
44
|
+
with OSMFeaturesClient(api_key="sk-...") as client:
|
|
45
|
+
fc = client.query(bbox="18.06,59.32,18.09,59.34", tags=["building"])
|
|
46
|
+
print(len(fc.features), "buildings found")
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
## Basic API usage
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
### 1) Create a client
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from osmfeatures import OSMFeaturesClient
|
|
59
|
+
|
|
60
|
+
client = OSMFeaturesClient(api_key="sk-...")
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
You can use the client directly and close it when done, or use a context manager:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from osmfeatures import OSMFeaturesClient
|
|
67
|
+
|
|
68
|
+
with OSMFeaturesClient(api_key="sk-...") as client:
|
|
69
|
+
...
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
### 2) Query OSM features
|
|
75
|
+
|
|
76
|
+
`query()` fetches a single page:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
fc = client.query(
|
|
80
|
+
bbox="18.063,59.322,18.082,59.332",
|
|
81
|
+
type="way",
|
|
82
|
+
shape="line",
|
|
83
|
+
tags=["highway=cycleway"],
|
|
84
|
+
limit=500,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
for feature in fc.features:
|
|
88
|
+
print(feature["id"], feature["geometry"]["type"], feature.tags)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Common filters:
|
|
92
|
+
|
|
93
|
+
- `bbox="min_lon,min_lat,max_lon,max_lat"`
|
|
94
|
+
- `around="lon,lat,radius_m"`
|
|
95
|
+
- `tags=["amenity=restaurant"]` (AND)
|
|
96
|
+
- `or_tags=["bicycle=yes", "bicycle=designated"]` (OR)
|
|
97
|
+
- `not_tags=["access=private"]` (exclude)
|
|
98
|
+
- `type="node" | "way" | "relation"`
|
|
99
|
+
- `shape="polygon" | "line" | "all"` (omit = both shapes; `all` also means both)
|
|
100
|
+
- `cursor` (pagination; use SDK `meta.next_cursor` from previous page, sourced from `X-Next-Cursor`)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
### 3) Auto-pagination and bbox tiling
|
|
105
|
+
|
|
106
|
+
Use `query_all()` to fetch all pages and deduplicate by OSM feature id. By default it splits the bbox into 2 tiles (power of 2) so large areas use more requests; pass `bbox_tiles=1` to disable, or raise it (`4`, `8`, …) for bigger areas:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
all_restaurants = client.query_all(
|
|
110
|
+
bbox="18.063,59.322,18.082,59.332",
|
|
111
|
+
tags="amenity=restaurant",
|
|
112
|
+
limit_per_page=1000, # page size per HTTP request
|
|
113
|
+
max_features=55_000, # total cap; pass None for no cap
|
|
114
|
+
bbox_tiles=2, # default
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
print(all_restaurants.meta.returned)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
### 4) Async client
|
|
123
|
+
|
|
124
|
+
Async methods mirror the sync API (`query_async`, `query_all_async`):
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
import asyncio
|
|
128
|
+
from osmfeatures import AsyncOSMFeaturesClient
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
async def main() -> None:
|
|
132
|
+
async with AsyncOSMFeaturesClient(api_key="sk-...") as client:
|
|
133
|
+
fc = await client.query_async(
|
|
134
|
+
bbox="18.06,59.32,18.09,59.34",
|
|
135
|
+
tags=["building"],
|
|
136
|
+
)
|
|
137
|
+
print(len(fc.features))
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
asyncio.run(main())
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
### 5) Convenience helpers
|
|
146
|
+
|
|
147
|
+
For common datasets, use convenience methods built on top of `query_all()`:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from osmfeatures import OSMFeaturesClient, get_buildings, get_restaurants
|
|
151
|
+
|
|
152
|
+
with OSMFeaturesClient(api_key="sk-...") as client:
|
|
153
|
+
buildings = get_buildings(client, bbox="18.063,59.322,18.082,59.332")
|
|
154
|
+
restaurants = get_restaurants(client, bbox="18.063,59.322,18.082,59.332")
|
|
155
|
+
print(len(buildings.features), len(restaurants.features))
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
### 6) Cost and usage
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
estimate = client.estimate_cost(
|
|
164
|
+
bbox="18.063,59.322,18.082,59.332",
|
|
165
|
+
tags=["building"],
|
|
166
|
+
)
|
|
167
|
+
print("estimated credits:", estimate.estimated_credits)
|
|
168
|
+
|
|
169
|
+
usage = client.usage()
|
|
170
|
+
print("Usage:", usage)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
### 7) CLI usage
|
|
176
|
+
|
|
177
|
+
If the package is installed, the CLI is available as `osmfeatures`:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
export MAPLARK_API_KEY="sk-..."
|
|
181
|
+
osmfeatures query --bbox "18.063,59.322,18.082,59.332" --tags building --type way
|
|
182
|
+
osmfeatures query --bbox "18.063,59.322,18.082,59.332" --tags building --all-pages --bbox-tiles 4
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
## Example apps
|
|
188
|
+
|
|
189
|
+
The repository includes runnable example-app tests in `tests/example_apps/` showing end-to-end usage patterns against real OSM data.
|
|
190
|
+
|
|
191
|
+
- `test_restaurant_guide.py`: restaurant discovery list with names/cuisines and map coordinates.
|
|
192
|
+
- `test_park_bench_finder.py`: bench finder for park maps (`amenity=bench`).
|
|
193
|
+
- `test_park_explorer.py`: park browser with polygon boundaries, centroids, and area estimates.
|
|
194
|
+
- `test_cycling_trails.py`: unpaved cycling trail layer for MTB/gravel planning.
|
|
195
|
+
- `test_city_cycling_infrastructure.py`: city cycling overlay combining cycleways and bike lanes.
|
|
196
|
+
- `test_lakeside_ice_cream_hunt.py`: nearest ice cream shops to waterfront edges.
|
|
197
|
+
- `test_pedestrian_shortest_path.py`: shortest walking route via graph + Dijkstra.
|
|
198
|
+
- `test_pedestrian_wavefront_bfs.py`: hop-based accessibility rings via BFS.
|
|
199
|
+
- `test_bike_path_dijkstra_liljeholmen_to_djurgarden.py`: tiled corridor bike routing from Liljeholmen to Djurgarden.
|
|
200
|
+
- `test_geometry_filters.py`: zoom + area/length filters for large buildings and long roads.
|
|
201
|
+
|
|
202
|
+
Run all example apps:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
pytest tests/example_apps -v
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Run one example app:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
pytest tests/example_apps/test_restaurant_guide.py -v
|
|
212
|
+
```
|
|
213
|
+
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "osmfeatures"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Official client for the MapLark OSM Features API (GeoJSON, FlatGeobuf, GeoParquet, CSV)"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
keywords = ["openstreetmap", "osm", "geojson", "flatgeobuf", "geoparquet", "overpass", "maplark", "geospatial", "maps"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 3 - Alpha",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.10",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Topic :: Scientific/Engineering :: GIS",
|
|
22
|
+
"Typing :: Typed",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"requests>=2.28",
|
|
26
|
+
"httpx>=0.27",
|
|
27
|
+
"click>=8.1",
|
|
28
|
+
"geojson>=3.0",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
geo = [
|
|
33
|
+
"pandas>=2.0",
|
|
34
|
+
"geopandas>=0.14",
|
|
35
|
+
"shapely>=2.0",
|
|
36
|
+
]
|
|
37
|
+
all = ["pandas>=2.0", "geopandas>=0.14", "shapely>=2.0"]
|
|
38
|
+
test = [
|
|
39
|
+
"pytest>=7.0",
|
|
40
|
+
"responses>=0.25",
|
|
41
|
+
"pytest-asyncio>=0.23",
|
|
42
|
+
"networkx>=3.0",
|
|
43
|
+
"haversine>=2.8",
|
|
44
|
+
"python-dotenv>=1.0",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[project.scripts]
|
|
48
|
+
osmfeatures = "osmfeatures.cli:cli"
|
|
49
|
+
|
|
50
|
+
[project.urls]
|
|
51
|
+
Homepage = "https://maplark.com"
|
|
52
|
+
Repository = "https://github.com/MapLark/osmfeatures-python"
|
|
53
|
+
|
|
54
|
+
[tool.hatch.build.targets.wheel]
|
|
55
|
+
packages = ["src/osmfeatures"]
|
|
56
|
+
include = ["src/osmfeatures/py.typed"]
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
testpaths = ["tests"]
|
|
60
|
+
pythonpath = ["."]
|
|
61
|
+
asyncio_mode = "auto"
|
|
62
|
+
|
|
63
|
+
[tool.mypy]
|
|
64
|
+
strict = true
|