osmfinder 1.0.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.
- osmfinder-1.0.0/PKG-INFO +271 -0
- osmfinder-1.0.0/README.md +232 -0
- osmfinder-1.0.0/osmfinder/__init__.py +54 -0
- osmfinder-1.0.0/osmfinder/_compat.py +15 -0
- osmfinder-1.0.0/osmfinder/_constants.py +14 -0
- osmfinder-1.0.0/osmfinder/_io.py +104 -0
- osmfinder-1.0.0/osmfinder/_results.py +180 -0
- osmfinder-1.0.0/osmfinder/_typing.py +263 -0
- osmfinder-1.0.0/osmfinder/exceptions.py +79 -0
- osmfinder-1.0.0/osmfinder/extract.py +211 -0
- osmfinder-1.0.0/osmfinder/finder.py +1777 -0
- osmfinder-1.0.0/osmfinder/parsers/__init__.py +1 -0
- osmfinder-1.0.0/osmfinder/parsers/geojson.py +72 -0
- osmfinder-1.0.0/osmfinder/parsers/poly.py +83 -0
- osmfinder-1.0.0/osmfinder/py.typed +0 -0
- osmfinder-1.0.0/osmfinder/sources/__init__.py +1 -0
- osmfinder-1.0.0/osmfinder/sources/bbbike.py +104 -0
- osmfinder-1.0.0/osmfinder/sources/geo2day.py +172 -0
- osmfinder-1.0.0/osmfinder/sources/geofabrik.py +93 -0
- osmfinder-1.0.0/osmfinder/sources/movisda.py +180 -0
- osmfinder-1.0.0/osmfinder/sources/osm_fr.py +131 -0
- osmfinder-1.0.0/osmfinder/sources/tree.py +120 -0
- osmfinder-1.0.0/pyproject.toml +187 -0
- osmfinder-1.0.0/pyproject.toml.orig +169 -0
osmfinder-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: osmfinder
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Find and download OpenStreetMap *.osm.pbf extracts by name, id or geometry.
|
|
5
|
+
Keywords: openstreetmap,osm,pbf,extract,geofabrik,bbbike,gis,download
|
|
6
|
+
Author: Kamil Raczycki
|
|
7
|
+
Author-email: Kamil Raczycki <kraczycki@kraina.ai>
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Operating System :: Unix
|
|
20
|
+
Classifier: Operating System :: MacOS
|
|
21
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
22
|
+
Requires-Dist: shapely>=2
|
|
23
|
+
Requires-Dist: pyproj>=3
|
|
24
|
+
Requires-Dist: pooch>=1.6.0
|
|
25
|
+
Requires-Dist: requests
|
|
26
|
+
Requires-Dist: beautifulsoup4
|
|
27
|
+
Requires-Dist: rich>=12.0.0
|
|
28
|
+
Requires-Dist: tqdm>=4.42.0
|
|
29
|
+
Requires-Dist: platformdirs>=2
|
|
30
|
+
Requires-Dist: anyascii>=0.3.3
|
|
31
|
+
Requires-Dist: python-dateutil>=2.8
|
|
32
|
+
Requires-Dist: arro3-core>=0.8.0
|
|
33
|
+
Requires-Dist: arro3-io>=0.8.0
|
|
34
|
+
Requires-Python: >=3.10
|
|
35
|
+
Project-URL: Homepage, https://github.com/RaczeQ/osmfinder
|
|
36
|
+
Project-URL: Repository, https://github.com/RaczeQ/osmfinder
|
|
37
|
+
Project-URL: Changelog, https://github.com/RaczeQ/osmfinder/blob/main/CHANGELOG.md
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# OSM Finder
|
|
43
|
+
|
|
44
|
+
Find and download publicly available OpenStreetMap `*.osm.pbf` extracts by **name**, **id** or
|
|
45
|
+
**geometry**.
|
|
46
|
+
|
|
47
|
+
`osmfinder` wraps several public extract providers behind a single API:
|
|
48
|
+
[Geofabrik](https://download.geofabrik.de/), [BBBike](https://download.bbbike.org/osm/bbbike/),
|
|
49
|
+
[OpenStreetMap.fr](https://download.openstreetmap.fr/), [Movisda](https://osm.download.movisda.io/)
|
|
50
|
+
and [GEO2day](https://geo2day.com/). It can look up an extract by a text query, or find the
|
|
51
|
+
smallest set of extracts covering an arbitrary geometry, and download the matching `*.osm.pbf`
|
|
52
|
+
files.
|
|
53
|
+
|
|
54
|
+
<p align="center">
|
|
55
|
+
<img width="300" src="https://raw.githubusercontent.com/raczeq/osmfinder/main/docs/assets/logos/osmfinder_logo.png"><br/>
|
|
56
|
+
</p>
|
|
57
|
+
|
|
58
|
+
<p align="center">
|
|
59
|
+
<img alt="GitHub" src="https://img.shields.io/github/license/raczeq/osmfinder?logo=mit&logoColor=%23fff">
|
|
60
|
+
<img src="https://img.shields.io/github/checks-status/raczeq/osmfinder/main?logo=GitHubActions&logoColor=%23fff" alt="Checks">
|
|
61
|
+
<a href="https://github.com/raczeq/osmfinder/actions/workflows/ci-prod.yml" target="_blank"><img alt="GitHub Workflow Status - PROD" src="https://img.shields.io/github/actions/workflow/status/raczeq/osmfinder/ci-prod.yml?label=build-prod&logo=GitHubActions&logoColor=%23fff"></a>
|
|
62
|
+
<a href="https://results.pre-commit.ci/latest/github/raczeq/osmfinder/main" target="_blank"><img src="https://results.pre-commit.ci/badge/github/raczeq/osmfinder/main.svg" alt="pre-commit.ci status"></a>
|
|
63
|
+
<a href="https://www.codefactor.io/repository/github/raczeq/osmfinder"><img alt="CodeFactor Grade" src="https://img.shields.io/codefactor/grade/github/raczeq/osmfinder?logo=codefactor&logoColor=%23fff"></a>
|
|
64
|
+
<a href="https://app.codecov.io/gh/raczeq/osmfinder/tree/main"><img alt="Codecov" src="https://img.shields.io/codecov/c/github/raczeq/osmfinder?logo=codecov&token=PRS4E02ZX0&logoColor=%23fff"></a>
|
|
65
|
+
<a href="https://pypi.org/project/osmfinder" target="_blank"><img src="https://img.shields.io/pypi/v/osmfinder?color=%2334D058&label=pypi%20package&logo=pypi&logoColor=%23fff" alt="Package version"></a>
|
|
66
|
+
<a href="https://pypi.org/project/osmfinder" target="_blank"><img src="https://img.shields.io/pypi/pyversions/osmfinder.svg?color=%2334D058&logo=python&logoColor=%23fff" alt="Supported Python versions"></a>
|
|
67
|
+
<a href="https://pypi.org/project/osmfinder" target="_blank"><img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/osmfinder"></a>
|
|
68
|
+
</p>
|
|
69
|
+
|
|
70
|
+
> **Logo attribution:** The osmfinder logo uses icons from the [Lucide](https://lucide.dev/) icon set —
|
|
71
|
+
> specifically the **earth** and **square-dashed** icons.
|
|
72
|
+
|
|
73
|
+
## Installation
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pip install osmfinder
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Usage
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
import osmfinder
|
|
83
|
+
from shapely.geometry import box
|
|
84
|
+
|
|
85
|
+
# --- by name / id ---
|
|
86
|
+
# Returns an OsmfinderQueryResult with .extracts list and .extract accessor.
|
|
87
|
+
result = osmfinder.find("Monaco")
|
|
88
|
+
print(result.extracts[0].id) # 'Movisda-admin_MC'
|
|
89
|
+
print(result.extracts[0].file_name) # 'movisda-admin_monaco'
|
|
90
|
+
print(result.extract.id) # convenience accessor for single-match queries
|
|
91
|
+
|
|
92
|
+
# Download by name - returns OsmfinderDownloadResult with .download_paths.
|
|
93
|
+
dl = osmfinder.download("Monaco", download_directory="files")
|
|
94
|
+
print(dl.download_paths) # [Path('files/movisda-admin_monaco.osm.pbf')]
|
|
95
|
+
print(dl.find_result.extract.id) # 'Movisda-admin_MC'
|
|
96
|
+
|
|
97
|
+
# --- by geometry ---
|
|
98
|
+
geometry = box(2.11, 48.77, 2.54, 48.98)
|
|
99
|
+
result = osmfinder.find(geometry)
|
|
100
|
+
print(result) # multi-line OsmfinderGeometryResult with extracts, coverage, steps
|
|
101
|
+
print(len(result.extracts)) # number of extracts covering the geometry
|
|
102
|
+
print(result.extracts[0].id) # 'BBBike_Paris'
|
|
103
|
+
|
|
104
|
+
# Download by geometry
|
|
105
|
+
dl = osmfinder.download(geometry, source="Geofabrik", download_directory="files")
|
|
106
|
+
print(len(dl.download_paths)) # number of downloaded files
|
|
107
|
+
print(dl.download_paths[0].name) # 'geofabrik_europe_monaco.osm.pbf'
|
|
108
|
+
|
|
109
|
+
# --- by point ---
|
|
110
|
+
extracts = osmfinder.find_extracts_covering_point((-0.1276, 51.5074), source="Geofabrik")
|
|
111
|
+
print(len(extracts)) # number of extracts covering central London
|
|
112
|
+
print(extracts[0].id) # 'Geofabrik_greater-london'
|
|
113
|
+
|
|
114
|
+
# --- force single extract ---
|
|
115
|
+
geometry = box(9.4, 47.2, 9.8, 47.6)
|
|
116
|
+
result = osmfinder.find_smallest_containing_extracts(
|
|
117
|
+
geometry, force_single_result=False # default behaviour
|
|
118
|
+
)
|
|
119
|
+
print(len(result.extracts)) # 4
|
|
120
|
+
print(result.extracts[0].id) # 'GEO2Day_europe_austria_vorarlberg'
|
|
121
|
+
print(result.extracts[1].id) # 'BBBike_Konstanz'
|
|
122
|
+
print(result.extracts[2].id) # 'GEO2Day_europe_switzerland_saint_gallen'
|
|
123
|
+
print(result.extracts[3].id) # 'Movisda-admin_LI'
|
|
124
|
+
|
|
125
|
+
result = osmfinder.find_smallest_containing_extracts(
|
|
126
|
+
geometry, force_single_result=True
|
|
127
|
+
)
|
|
128
|
+
print(len(result.extracts)) # 1
|
|
129
|
+
print(result.extracts[0].id) # 'Movisda-grid_N47W009'
|
|
130
|
+
|
|
131
|
+
# --- explore what's available ---
|
|
132
|
+
osmfinder.display_available_extracts(source="Geofabrik") # source is optional
|
|
133
|
+
|
|
134
|
+
# Get all extracts as a list for programmatic use
|
|
135
|
+
extracts = osmfinder.get_available_extracts(source="Geofabrik") # source is optional
|
|
136
|
+
for extract in extracts:
|
|
137
|
+
print(extract.id, extract.file_name)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Sources
|
|
141
|
+
|
|
142
|
+
The `source` argument accepts a single value, an iterable, or a comma-separated string. Available
|
|
143
|
+
values: `any`, `Geofabrik`, `BBBike`, `osmfr`, `GEO2Day`, `Movisda-admin`, `Movisda-grid`.
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
osmfinder.get_extract_by_query("Berlin", ["Geofabrik", "BBBike"])
|
|
147
|
+
osmfinder.get_extract_by_query("Berlin", "geofabrik,bbbike")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Result classes
|
|
151
|
+
|
|
152
|
+
All find and download operations return typed result objects instead of raw lists.
|
|
153
|
+
|
|
154
|
+
### `OsmfinderQueryResult`
|
|
155
|
+
|
|
156
|
+
Returned by `get_extract_by_query()` and `find()` when called with a string query.
|
|
157
|
+
|
|
158
|
+
| Attribute | Type | Description |
|
|
159
|
+
|---|---|---|
|
|
160
|
+
| `extracts` | `list[OpenStreetMapExtract]` | All matched extracts |
|
|
161
|
+
| `extract` | `OpenStreetMapExtract` | Convenience accessor for the single matched extract |
|
|
162
|
+
| `matched_extracts` | `list[OpenStreetMapExtract]` | All extracts matched by the query before selection (may contain more than `extracts` when `select_first_match=True`) |
|
|
163
|
+
| `query` | `str` | The original query string |
|
|
164
|
+
| `sources_used` | `list[OsmExtractSource]` | Sources that were searched |
|
|
165
|
+
|
|
166
|
+
### `OsmfinderGeometryResult`
|
|
167
|
+
|
|
168
|
+
Returned by `find_smallest_containing_extracts()` and `find()` when called with a geometry.
|
|
169
|
+
|
|
170
|
+
| Attribute | Type | Description |
|
|
171
|
+
|---|---|---|
|
|
172
|
+
| `extracts` | `list[OpenStreetMapExtract]` | Selected extracts covering the geometry |
|
|
173
|
+
| `input_geometry` | `BaseGeometry` | The original input geometry |
|
|
174
|
+
| `covered_geometry` | `BaseGeometry` | Union of extract geometries intersecting the input |
|
|
175
|
+
| `uncovered_geometry` | `BaseGeometry` | Parts of the input not covered by any extract |
|
|
176
|
+
| `steps` | `list[GeometryCoveringStep]` | Record of each extract considered during covering |
|
|
177
|
+
| `iou_threshold` | `float` | IoU threshold used for selection |
|
|
178
|
+
| `sources_used` | `list[OsmExtractSource]` | Sources that were searched |
|
|
179
|
+
|
|
180
|
+
### `OsmfinderDownloadResult`
|
|
181
|
+
|
|
182
|
+
Returned by `download_extract_by_query()`, `find_and_download_extracts_pbf_files()`, and `download()`.
|
|
183
|
+
|
|
184
|
+
| Attribute | Type | Description |
|
|
185
|
+
|---|---|---|
|
|
186
|
+
| `find_result` | `OsmfinderQueryResult \| OsmfinderGeometryResult` | The underlying find result |
|
|
187
|
+
| `download_paths` | `list[Path]` | Paths to downloaded `.osm.pbf` files |
|
|
188
|
+
| `unavailable_extracts` | `list[OpenStreetMapExtract]` | Extracts that could not be downloaded |
|
|
189
|
+
|
|
190
|
+
### `GeometryCoveringStep`
|
|
191
|
+
|
|
192
|
+
Record of a single extract considered during geometry covering.
|
|
193
|
+
|
|
194
|
+
| Attribute | Type | Description |
|
|
195
|
+
|---|---|---|
|
|
196
|
+
| `extract` | `OpenStreetMapExtract` | The extract considered |
|
|
197
|
+
| `iou` | `float` | Intersection over Union with the remaining geometry |
|
|
198
|
+
| `selected` | `bool` | Whether the extract was selected |
|
|
199
|
+
| `reason` | `str` | Selection reason (`"selected"` or `"low_iou"`) |
|
|
200
|
+
| `geometry_to_cover` | `BaseGeometry` | Remaining geometry before this step |
|
|
201
|
+
| `intersection_geometry` | `BaseGeometry` | Intersection of the extract with the remaining geometry |
|
|
202
|
+
|
|
203
|
+
### Example `repr` output
|
|
204
|
+
|
|
205
|
+
All result objects use a verbose multi-line `repr` for easier debugging:
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
>>> result = osmfinder.find("Monaco")
|
|
209
|
+
>>> print(result)
|
|
210
|
+
OsmfinderQueryResult
|
|
211
|
+
query: Monaco
|
|
212
|
+
extract: Movisda-admin_MC — Monaco
|
|
213
|
+
matched extracts: Movisda-admin_MC, Geofabrik_monaco, BBBike_Monaco, OSM_fr_monaco, geofabrik_andorra, +3 more
|
|
214
|
+
sources used: Geofabrik, BBBike, OSM_fr, Movisda-admin, GEO2Day
|
|
215
|
+
|
|
216
|
+
>>> geometry = box(7.40, 43.71, 7.44, 43.75)
|
|
217
|
+
>>> result = osmfinder.find(geometry, source="Geofabrik")
|
|
218
|
+
>>> print(result)
|
|
219
|
+
OsmfinderGeometryResult
|
|
220
|
+
extracts:
|
|
221
|
+
Geofabrik_europe_monaco — Monaco
|
|
222
|
+
coverage: 100.0%
|
|
223
|
+
iou threshold: 0.01
|
|
224
|
+
steps:
|
|
225
|
+
Geofabrik_europe_monaco — Monaco
|
|
226
|
+
iou: 1.0000, selected, first_extract
|
|
227
|
+
sources used: Geofabrik
|
|
228
|
+
|
|
229
|
+
>>> dl = osmfinder.download("Monaco", download_directory="files")
|
|
230
|
+
>>> print(dl)
|
|
231
|
+
OsmfinderDownloadResult
|
|
232
|
+
downloaded:
|
|
233
|
+
files/movisda-admin_monaco.osm.pbf
|
|
234
|
+
unavailable:
|
|
235
|
+
none
|
|
236
|
+
find result:
|
|
237
|
+
OsmfinderQueryResult
|
|
238
|
+
query: Monaco
|
|
239
|
+
extract: Movisda-admin_MC — Monaco
|
|
240
|
+
matched extracts: Movisda-admin_MC, Geofabrik_monaco, BBBike_Monaco, OSM_fr_monaco, geofabrik_andorra, +3 more
|
|
241
|
+
sources used: Geofabrik, BBBike, OSM_fr, Movisda-admin, GEO2Day
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Public API
|
|
245
|
+
|
|
246
|
+
| Function | Search by | Returns |
|
|
247
|
+
|---|---|---|
|
|
248
|
+
| `get_extract_by_query` | name / id | `OsmfinderQueryResult` |
|
|
249
|
+
| `get_available_extracts` | — | `list[OpenStreetMapExtract]` |
|
|
250
|
+
| `download_extract_by_query` | name / id | `OsmfinderDownloadResult` |
|
|
251
|
+
| `find_smallest_containing_extracts` | geometry | `OsmfinderGeometryResult` |
|
|
252
|
+
| `find_and_download_extracts_pbf_files` | geometry | `OsmfinderDownloadResult` |
|
|
253
|
+
| `download_extracts_pbf_files` | list of extracts | `list[Path]` |
|
|
254
|
+
| `display_available_extracts` | — | prints a tree |
|
|
255
|
+
| `clear_osm_index_cache` | — | clears the local index cache |
|
|
256
|
+
|
|
257
|
+
> **Note:** `find()` and `download()` are dual-purpose helpers. When called with a **string query** they
|
|
258
|
+
> return an `OsmfinderQueryResult` / `OsmfinderDownloadResult`. When called with a **geometry** they
|
|
259
|
+
> return an `OsmfinderGeometryResult` / `OsmfinderDownloadResult`. Use the explicit
|
|
260
|
+
> `get_extract_by_query` / `download_extract_by_query` if you want a single object without the list wrapper.
|
|
261
|
+
|
|
262
|
+
## Index cache
|
|
263
|
+
|
|
264
|
+
Provider indexes are cached locally (in the platform cache dir) as GeoParquet (`*.parquet`).
|
|
265
|
+
Precalculated indexes are downloaded from this repo's `precalculated_indexes/` folder on first use,
|
|
266
|
+
so most sources don't need to be rebuilt from scratch. Use `clear_osm_index_cache()` to force a
|
|
267
|
+
refresh.
|
|
268
|
+
|
|
269
|
+
## License
|
|
270
|
+
|
|
271
|
+
MIT
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
# OSM Finder
|
|
4
|
+
|
|
5
|
+
Find and download publicly available OpenStreetMap `*.osm.pbf` extracts by **name**, **id** or
|
|
6
|
+
**geometry**.
|
|
7
|
+
|
|
8
|
+
`osmfinder` wraps several public extract providers behind a single API:
|
|
9
|
+
[Geofabrik](https://download.geofabrik.de/), [BBBike](https://download.bbbike.org/osm/bbbike/),
|
|
10
|
+
[OpenStreetMap.fr](https://download.openstreetmap.fr/), [Movisda](https://osm.download.movisda.io/)
|
|
11
|
+
and [GEO2day](https://geo2day.com/). It can look up an extract by a text query, or find the
|
|
12
|
+
smallest set of extracts covering an arbitrary geometry, and download the matching `*.osm.pbf`
|
|
13
|
+
files.
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
<img width="300" src="https://raw.githubusercontent.com/raczeq/osmfinder/main/docs/assets/logos/osmfinder_logo.png"><br/>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<img alt="GitHub" src="https://img.shields.io/github/license/raczeq/osmfinder?logo=mit&logoColor=%23fff">
|
|
21
|
+
<img src="https://img.shields.io/github/checks-status/raczeq/osmfinder/main?logo=GitHubActions&logoColor=%23fff" alt="Checks">
|
|
22
|
+
<a href="https://github.com/raczeq/osmfinder/actions/workflows/ci-prod.yml" target="_blank"><img alt="GitHub Workflow Status - PROD" src="https://img.shields.io/github/actions/workflow/status/raczeq/osmfinder/ci-prod.yml?label=build-prod&logo=GitHubActions&logoColor=%23fff"></a>
|
|
23
|
+
<a href="https://results.pre-commit.ci/latest/github/raczeq/osmfinder/main" target="_blank"><img src="https://results.pre-commit.ci/badge/github/raczeq/osmfinder/main.svg" alt="pre-commit.ci status"></a>
|
|
24
|
+
<a href="https://www.codefactor.io/repository/github/raczeq/osmfinder"><img alt="CodeFactor Grade" src="https://img.shields.io/codefactor/grade/github/raczeq/osmfinder?logo=codefactor&logoColor=%23fff"></a>
|
|
25
|
+
<a href="https://app.codecov.io/gh/raczeq/osmfinder/tree/main"><img alt="Codecov" src="https://img.shields.io/codecov/c/github/raczeq/osmfinder?logo=codecov&token=PRS4E02ZX0&logoColor=%23fff"></a>
|
|
26
|
+
<a href="https://pypi.org/project/osmfinder" target="_blank"><img src="https://img.shields.io/pypi/v/osmfinder?color=%2334D058&label=pypi%20package&logo=pypi&logoColor=%23fff" alt="Package version"></a>
|
|
27
|
+
<a href="https://pypi.org/project/osmfinder" target="_blank"><img src="https://img.shields.io/pypi/pyversions/osmfinder.svg?color=%2334D058&logo=python&logoColor=%23fff" alt="Supported Python versions"></a>
|
|
28
|
+
<a href="https://pypi.org/project/osmfinder" target="_blank"><img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/osmfinder"></a>
|
|
29
|
+
</p>
|
|
30
|
+
|
|
31
|
+
> **Logo attribution:** The osmfinder logo uses icons from the [Lucide](https://lucide.dev/) icon set —
|
|
32
|
+
> specifically the **earth** and **square-dashed** icons.
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install osmfinder
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Usage
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
import osmfinder
|
|
44
|
+
from shapely.geometry import box
|
|
45
|
+
|
|
46
|
+
# --- by name / id ---
|
|
47
|
+
# Returns an OsmfinderQueryResult with .extracts list and .extract accessor.
|
|
48
|
+
result = osmfinder.find("Monaco")
|
|
49
|
+
print(result.extracts[0].id) # 'Movisda-admin_MC'
|
|
50
|
+
print(result.extracts[0].file_name) # 'movisda-admin_monaco'
|
|
51
|
+
print(result.extract.id) # convenience accessor for single-match queries
|
|
52
|
+
|
|
53
|
+
# Download by name - returns OsmfinderDownloadResult with .download_paths.
|
|
54
|
+
dl = osmfinder.download("Monaco", download_directory="files")
|
|
55
|
+
print(dl.download_paths) # [Path('files/movisda-admin_monaco.osm.pbf')]
|
|
56
|
+
print(dl.find_result.extract.id) # 'Movisda-admin_MC'
|
|
57
|
+
|
|
58
|
+
# --- by geometry ---
|
|
59
|
+
geometry = box(2.11, 48.77, 2.54, 48.98)
|
|
60
|
+
result = osmfinder.find(geometry)
|
|
61
|
+
print(result) # multi-line OsmfinderGeometryResult with extracts, coverage, steps
|
|
62
|
+
print(len(result.extracts)) # number of extracts covering the geometry
|
|
63
|
+
print(result.extracts[0].id) # 'BBBike_Paris'
|
|
64
|
+
|
|
65
|
+
# Download by geometry
|
|
66
|
+
dl = osmfinder.download(geometry, source="Geofabrik", download_directory="files")
|
|
67
|
+
print(len(dl.download_paths)) # number of downloaded files
|
|
68
|
+
print(dl.download_paths[0].name) # 'geofabrik_europe_monaco.osm.pbf'
|
|
69
|
+
|
|
70
|
+
# --- by point ---
|
|
71
|
+
extracts = osmfinder.find_extracts_covering_point((-0.1276, 51.5074), source="Geofabrik")
|
|
72
|
+
print(len(extracts)) # number of extracts covering central London
|
|
73
|
+
print(extracts[0].id) # 'Geofabrik_greater-london'
|
|
74
|
+
|
|
75
|
+
# --- force single extract ---
|
|
76
|
+
geometry = box(9.4, 47.2, 9.8, 47.6)
|
|
77
|
+
result = osmfinder.find_smallest_containing_extracts(
|
|
78
|
+
geometry, force_single_result=False # default behaviour
|
|
79
|
+
)
|
|
80
|
+
print(len(result.extracts)) # 4
|
|
81
|
+
print(result.extracts[0].id) # 'GEO2Day_europe_austria_vorarlberg'
|
|
82
|
+
print(result.extracts[1].id) # 'BBBike_Konstanz'
|
|
83
|
+
print(result.extracts[2].id) # 'GEO2Day_europe_switzerland_saint_gallen'
|
|
84
|
+
print(result.extracts[3].id) # 'Movisda-admin_LI'
|
|
85
|
+
|
|
86
|
+
result = osmfinder.find_smallest_containing_extracts(
|
|
87
|
+
geometry, force_single_result=True
|
|
88
|
+
)
|
|
89
|
+
print(len(result.extracts)) # 1
|
|
90
|
+
print(result.extracts[0].id) # 'Movisda-grid_N47W009'
|
|
91
|
+
|
|
92
|
+
# --- explore what's available ---
|
|
93
|
+
osmfinder.display_available_extracts(source="Geofabrik") # source is optional
|
|
94
|
+
|
|
95
|
+
# Get all extracts as a list for programmatic use
|
|
96
|
+
extracts = osmfinder.get_available_extracts(source="Geofabrik") # source is optional
|
|
97
|
+
for extract in extracts:
|
|
98
|
+
print(extract.id, extract.file_name)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Sources
|
|
102
|
+
|
|
103
|
+
The `source` argument accepts a single value, an iterable, or a comma-separated string. Available
|
|
104
|
+
values: `any`, `Geofabrik`, `BBBike`, `osmfr`, `GEO2Day`, `Movisda-admin`, `Movisda-grid`.
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
osmfinder.get_extract_by_query("Berlin", ["Geofabrik", "BBBike"])
|
|
108
|
+
osmfinder.get_extract_by_query("Berlin", "geofabrik,bbbike")
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Result classes
|
|
112
|
+
|
|
113
|
+
All find and download operations return typed result objects instead of raw lists.
|
|
114
|
+
|
|
115
|
+
### `OsmfinderQueryResult`
|
|
116
|
+
|
|
117
|
+
Returned by `get_extract_by_query()` and `find()` when called with a string query.
|
|
118
|
+
|
|
119
|
+
| Attribute | Type | Description |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| `extracts` | `list[OpenStreetMapExtract]` | All matched extracts |
|
|
122
|
+
| `extract` | `OpenStreetMapExtract` | Convenience accessor for the single matched extract |
|
|
123
|
+
| `matched_extracts` | `list[OpenStreetMapExtract]` | All extracts matched by the query before selection (may contain more than `extracts` when `select_first_match=True`) |
|
|
124
|
+
| `query` | `str` | The original query string |
|
|
125
|
+
| `sources_used` | `list[OsmExtractSource]` | Sources that were searched |
|
|
126
|
+
|
|
127
|
+
### `OsmfinderGeometryResult`
|
|
128
|
+
|
|
129
|
+
Returned by `find_smallest_containing_extracts()` and `find()` when called with a geometry.
|
|
130
|
+
|
|
131
|
+
| Attribute | Type | Description |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| `extracts` | `list[OpenStreetMapExtract]` | Selected extracts covering the geometry |
|
|
134
|
+
| `input_geometry` | `BaseGeometry` | The original input geometry |
|
|
135
|
+
| `covered_geometry` | `BaseGeometry` | Union of extract geometries intersecting the input |
|
|
136
|
+
| `uncovered_geometry` | `BaseGeometry` | Parts of the input not covered by any extract |
|
|
137
|
+
| `steps` | `list[GeometryCoveringStep]` | Record of each extract considered during covering |
|
|
138
|
+
| `iou_threshold` | `float` | IoU threshold used for selection |
|
|
139
|
+
| `sources_used` | `list[OsmExtractSource]` | Sources that were searched |
|
|
140
|
+
|
|
141
|
+
### `OsmfinderDownloadResult`
|
|
142
|
+
|
|
143
|
+
Returned by `download_extract_by_query()`, `find_and_download_extracts_pbf_files()`, and `download()`.
|
|
144
|
+
|
|
145
|
+
| Attribute | Type | Description |
|
|
146
|
+
|---|---|---|
|
|
147
|
+
| `find_result` | `OsmfinderQueryResult \| OsmfinderGeometryResult` | The underlying find result |
|
|
148
|
+
| `download_paths` | `list[Path]` | Paths to downloaded `.osm.pbf` files |
|
|
149
|
+
| `unavailable_extracts` | `list[OpenStreetMapExtract]` | Extracts that could not be downloaded |
|
|
150
|
+
|
|
151
|
+
### `GeometryCoveringStep`
|
|
152
|
+
|
|
153
|
+
Record of a single extract considered during geometry covering.
|
|
154
|
+
|
|
155
|
+
| Attribute | Type | Description |
|
|
156
|
+
|---|---|---|
|
|
157
|
+
| `extract` | `OpenStreetMapExtract` | The extract considered |
|
|
158
|
+
| `iou` | `float` | Intersection over Union with the remaining geometry |
|
|
159
|
+
| `selected` | `bool` | Whether the extract was selected |
|
|
160
|
+
| `reason` | `str` | Selection reason (`"selected"` or `"low_iou"`) |
|
|
161
|
+
| `geometry_to_cover` | `BaseGeometry` | Remaining geometry before this step |
|
|
162
|
+
| `intersection_geometry` | `BaseGeometry` | Intersection of the extract with the remaining geometry |
|
|
163
|
+
|
|
164
|
+
### Example `repr` output
|
|
165
|
+
|
|
166
|
+
All result objects use a verbose multi-line `repr` for easier debugging:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
>>> result = osmfinder.find("Monaco")
|
|
170
|
+
>>> print(result)
|
|
171
|
+
OsmfinderQueryResult
|
|
172
|
+
query: Monaco
|
|
173
|
+
extract: Movisda-admin_MC — Monaco
|
|
174
|
+
matched extracts: Movisda-admin_MC, Geofabrik_monaco, BBBike_Monaco, OSM_fr_monaco, geofabrik_andorra, +3 more
|
|
175
|
+
sources used: Geofabrik, BBBike, OSM_fr, Movisda-admin, GEO2Day
|
|
176
|
+
|
|
177
|
+
>>> geometry = box(7.40, 43.71, 7.44, 43.75)
|
|
178
|
+
>>> result = osmfinder.find(geometry, source="Geofabrik")
|
|
179
|
+
>>> print(result)
|
|
180
|
+
OsmfinderGeometryResult
|
|
181
|
+
extracts:
|
|
182
|
+
Geofabrik_europe_monaco — Monaco
|
|
183
|
+
coverage: 100.0%
|
|
184
|
+
iou threshold: 0.01
|
|
185
|
+
steps:
|
|
186
|
+
Geofabrik_europe_monaco — Monaco
|
|
187
|
+
iou: 1.0000, selected, first_extract
|
|
188
|
+
sources used: Geofabrik
|
|
189
|
+
|
|
190
|
+
>>> dl = osmfinder.download("Monaco", download_directory="files")
|
|
191
|
+
>>> print(dl)
|
|
192
|
+
OsmfinderDownloadResult
|
|
193
|
+
downloaded:
|
|
194
|
+
files/movisda-admin_monaco.osm.pbf
|
|
195
|
+
unavailable:
|
|
196
|
+
none
|
|
197
|
+
find result:
|
|
198
|
+
OsmfinderQueryResult
|
|
199
|
+
query: Monaco
|
|
200
|
+
extract: Movisda-admin_MC — Monaco
|
|
201
|
+
matched extracts: Movisda-admin_MC, Geofabrik_monaco, BBBike_Monaco, OSM_fr_monaco, geofabrik_andorra, +3 more
|
|
202
|
+
sources used: Geofabrik, BBBike, OSM_fr, Movisda-admin, GEO2Day
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Public API
|
|
206
|
+
|
|
207
|
+
| Function | Search by | Returns |
|
|
208
|
+
|---|---|---|
|
|
209
|
+
| `get_extract_by_query` | name / id | `OsmfinderQueryResult` |
|
|
210
|
+
| `get_available_extracts` | — | `list[OpenStreetMapExtract]` |
|
|
211
|
+
| `download_extract_by_query` | name / id | `OsmfinderDownloadResult` |
|
|
212
|
+
| `find_smallest_containing_extracts` | geometry | `OsmfinderGeometryResult` |
|
|
213
|
+
| `find_and_download_extracts_pbf_files` | geometry | `OsmfinderDownloadResult` |
|
|
214
|
+
| `download_extracts_pbf_files` | list of extracts | `list[Path]` |
|
|
215
|
+
| `display_available_extracts` | — | prints a tree |
|
|
216
|
+
| `clear_osm_index_cache` | — | clears the local index cache |
|
|
217
|
+
|
|
218
|
+
> **Note:** `find()` and `download()` are dual-purpose helpers. When called with a **string query** they
|
|
219
|
+
> return an `OsmfinderQueryResult` / `OsmfinderDownloadResult`. When called with a **geometry** they
|
|
220
|
+
> return an `OsmfinderGeometryResult` / `OsmfinderDownloadResult`. Use the explicit
|
|
221
|
+
> `get_extract_by_query` / `download_extract_by_query` if you want a single object without the list wrapper.
|
|
222
|
+
|
|
223
|
+
## Index cache
|
|
224
|
+
|
|
225
|
+
Provider indexes are cached locally (in the platform cache dir) as GeoParquet (`*.parquet`).
|
|
226
|
+
Precalculated indexes are downloaded from this repo's `precalculated_indexes/` folder on first use,
|
|
227
|
+
so most sources don't need to be rebuilt from scratch. Use `clear_osm_index_cache()` to force a
|
|
228
|
+
refresh.
|
|
229
|
+
|
|
230
|
+
## License
|
|
231
|
+
|
|
232
|
+
MIT
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""
|
|
2
|
+
osmfinder.
|
|
3
|
+
|
|
4
|
+
Find and download publicly available OpenStreetMap `*.osm.pbf` extracts by name, id or geometry.
|
|
5
|
+
|
|
6
|
+
The library wraps several public extract providers (Geofabrik, BBBike, OpenStreetMap.fr, Movisda,
|
|
7
|
+
GEO2day) behind a single API. It can look up an extract by a text query, or find the smallest set of
|
|
8
|
+
extracts covering an arbitrary geometry, and download the matching `*.osm.pbf` files.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from osmfinder._results import (
|
|
12
|
+
GeometryCoveringStep,
|
|
13
|
+
OsmfinderDownloadResult,
|
|
14
|
+
OsmfinderGeometryResult,
|
|
15
|
+
OsmfinderQueryResult,
|
|
16
|
+
)
|
|
17
|
+
from osmfinder._typing import OpenStreetMapExtract, OsmExtractSource
|
|
18
|
+
from osmfinder.extract import clear_osm_index_cache
|
|
19
|
+
from osmfinder.finder import (
|
|
20
|
+
OsmExtractSourceLike,
|
|
21
|
+
display_available_extracts,
|
|
22
|
+
download,
|
|
23
|
+
download_extract_by_query,
|
|
24
|
+
download_extracts_pbf_files,
|
|
25
|
+
find,
|
|
26
|
+
find_and_download_extracts_pbf_files,
|
|
27
|
+
find_extracts_covering_point,
|
|
28
|
+
find_smallest_containing_extracts,
|
|
29
|
+
get_available_extracts,
|
|
30
|
+
get_extract_by_query,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
__version__ = "1.0.0"
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
"GeometryCoveringStep",
|
|
37
|
+
"OpenStreetMapExtract",
|
|
38
|
+
"OsmExtractSource",
|
|
39
|
+
"OsmExtractSourceLike",
|
|
40
|
+
"OsmfinderDownloadResult",
|
|
41
|
+
"OsmfinderGeometryResult",
|
|
42
|
+
"OsmfinderQueryResult",
|
|
43
|
+
"clear_osm_index_cache",
|
|
44
|
+
"display_available_extracts",
|
|
45
|
+
"download",
|
|
46
|
+
"download_extract_by_query",
|
|
47
|
+
"download_extracts_pbf_files",
|
|
48
|
+
"find",
|
|
49
|
+
"find_and_download_extracts_pbf_files",
|
|
50
|
+
"find_extracts_covering_point",
|
|
51
|
+
"find_smallest_containing_extracts",
|
|
52
|
+
"get_available_extracts",
|
|
53
|
+
"get_extract_by_query",
|
|
54
|
+
]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Small compatibility helpers.
|
|
3
|
+
|
|
4
|
+
These were previously imported from ``rq_geo_toolkit``. They are vendored here (a few lines each)
|
|
5
|
+
so that ``osmfinder`` stays lightweight and doesn't pull the whole toolkit as a dependency.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
# Force terminal-style (non-jupyter, non-interactive) rich output when set.
|
|
11
|
+
FORCE_TERMINAL = os.getenv("FORCE_TERMINAL_MODE", "false").lower() == "true"
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"FORCE_TERMINAL",
|
|
15
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Constants used across osmfinder."""
|
|
2
|
+
|
|
3
|
+
WGS84_CRS = "EPSG:4326"
|
|
4
|
+
|
|
5
|
+
OSM_EXTRACTS_REQUEST_TIMEOUT_SECONDS = 30
|
|
6
|
+
|
|
7
|
+
# Sent as the User-Agent header on every request to the extract providers.
|
|
8
|
+
USER_AGENT = "osmfinder Python package (https://github.com/RaczeQ/osmfinder)"
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"OSM_EXTRACTS_REQUEST_TIMEOUT_SECONDS",
|
|
12
|
+
"USER_AGENT",
|
|
13
|
+
"WGS84_CRS",
|
|
14
|
+
]
|