SkillAgentSearch skills...

Quackosm

QuackOSM: an open-source Python and CLI tool for reading OpenStreetMap PBF files using DuckDB

Install / Use

/learn @kraina-ai/Quackosm
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<p align="center"> <img width="300" src="https://raw.githubusercontent.com/kraina-ai/quackosm/main/docs/assets/logos/quackosm_logo.png"><br/> <small>Generated using DALL·E 3 model with this prompt: A logo for a python library with White background, high quality, 8k. Cute duck and globe with cartography elements. Library for reading OpenStreetMap data using DuckDB.</small> </p> <p align="center"> <img alt="GitHub" src="https://img.shields.io/github/license/kraina-ai/quackosm?logo=apache&logoColor=%23fff"> <img src="https://img.shields.io/github/checks-status/kraina-ai/quackosm/main?logo=GitHubActions&logoColor=%23fff" alt="Checks"> <a href="https://github.com/kraina-ai/quackosm/actions/workflows/ci-dev.yml" target="_blank"><img alt="GitHub Workflow Status - DEV" src="https://img.shields.io/github/actions/workflow/status/kraina-ai/quackosm/ci-dev.yml?label=build-dev&logo=GitHubActions&logoColor=%23fff"></a> <a href="https://github.com/kraina-ai/quackosm/actions/workflows/ci-prod.yml" target="_blank"><img alt="GitHub Workflow Status - PROD" src="https://img.shields.io/github/actions/workflow/status/kraina-ai/quackosm/ci-prod.yml?label=build-prod&logo=GitHubActions&logoColor=%23fff"></a> <a href="https://results.pre-commit.ci/latest/github/kraina-ai/quackosm/main" target="_blank"><img src="https://results.pre-commit.ci/badge/github/kraina-ai/quackosm/main.svg" alt="pre-commit.ci status"></a> <a href="https://www.codefactor.io/repository/github/kraina-ai/quackosm"><img alt="CodeFactor Grade" src="https://img.shields.io/codefactor/grade/github/kraina-ai/quackosm?logo=codefactor&logoColor=%23fff"></a> <a href="https://app.codecov.io/gh/kraina-ai/quackosm/tree/main"><img alt="Codecov" src="https://img.shields.io/codecov/c/github/kraina-ai/quackosm?logo=codecov&token=PRS4E02ZX0&logoColor=%23fff"></a> <a href="https://pypi.org/project/quackosm" target="_blank"><img src="https://img.shields.io/pypi/v/quackosm?label=pypi%20package&logo=pypi&logoColor=%23fff" alt="Package version"></a> <a href="https://anaconda.org/conda-forge/quackosm" target="_blank"><img src="https://img.shields.io/conda/vn/conda-forge/quackosm?&logo=anaconda&logoColor=%23fff" alt="Package version"></a> <a href="https://pypi.org/project/quackosm" target="_blank"><img src="https://img.shields.io/pypi/pyversions/quackosm.svg?logo=python&logoColor=%23fff" alt="Supported Python versions"></a> <a href="https://pypi.org/project/quackosm" target="_blank"><img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/quackosm"></a> </p>

QuackOSM

An open-source tool for reading OpenStreetMap PBF files using DuckDB.

What is QuackOSM 🦆?

  • Scalable reader for OpenStreetMap ProtoBuffer (pbf) files.
  • Is based on top of DuckDB[^1] with its Spatial[^2] extension.
  • Saves files in the GeoParquet[^3] file format for easier integration with modern cloud stacks.
  • Utilizes multithreading unlike GDAL that works in a single thread only.
  • Can filter data based on geometry without the need for ogr2ogr clipping before operation.
  • Can filter data based on OSM tags (with negations and wildcards).
  • Can automatically download required PBF files for a given geometry.
  • Utilizes caching to reduce repeatable computations.
  • Can be used as Python module as well as a beautiful CLI based on Typer[^4].

[^1]: DuckDB Website [^2]: DuckDB Spatial extension repository [^3]: GeoParquet data format [^4]: Typer docs

Installing

As pure Python module

pip install quackosm
# or
uv pip install quackosm

With beautiful CLI

pip install quackosm[cli]
# or
uv pip install quackosm[cli]

From conda-forge

# Automatically installs with CLI
conda install conda-forge::quackosm

Required Python version?

QuackOSM supports Python >= 3.10

Dependencies

Required:

  • duckdb (>=1.1.2): For all DuckDB operations on PBF files and sorting result file (with spatial extension)

  • pyarrow (>=16.0.0): For parquet files wrangling

  • geoarrow-pyarrow (>=0.1.2): For GeoParquet IO operations and transforming Arrow data to Shapely objects

  • geopandas (>=0.6): For returning GeoDataFrames and reading Geo files

  • shapely (>=2.0): For parsing WKT and GeoJSON strings and fixing geometries

  • typeguard (>=3.0): For internal validation of types

  • psutil (>=5.6.2): For automatic scaling of parameters based on available resources

  • pooch (>=1.6.0): For downloading *.osm.pbf files and precalculated OSM indexes

  • rich (>=12.0.0) & tqdm (>=4.42.0): For showing progress bars

  • requests: For iterating OSM PBF files services

  • beautifulsoup4: For parsing HTML files and scraping required information

  • geopy (>=2.0.0): For geocoding of strings

Optional:

  • typer[all] (>=0.9.0) (click, colorama, rich, shellingham): Required in CLI

  • h3 extension for duckdb: For transforming H3 indexes into geometries. Required in CLI

  • s2sphere (>=0.2.5): For transforming S2 indexes into geometries. Required in CLI

Usage

If you already have downloaded the PBF file 📁🗺️

Load data as a GeoDataFrame

>>> import quackosm as qosm
>>> qosm.convert_pbf_to_geodataframe(monaco_pbf_path)
                                              tags                      geometry
feature_id
node/10005045289                {'shop': 'bakery'}      POINT (7.42245 43.73105)
node/10020887517  {'leisure': 'swimming_pool', ...      POINT (7.41316 43.73384)
node/10021298117  {'leisure': 'swimming_pool', ...      POINT (7.42777 43.74277)
node/10021298717  {'leisure': 'swimming_pool', ...      POINT (7.42630 43.74097)
node/10025656383  {'ferry': 'yes', 'name': 'Qua...      POINT (7.42550 43.73690)
...                                            ...                           ...
way/990669427     {'amenity': 'shelter', 'shelt...  POLYGON ((7.41461 43.7338...
way/990669428     {'highway': 'secondary', 'jun...  LINESTRING (7.41366 43.73...
way/990669429     {'highway': 'secondary', 'jun...  LINESTRING (7.41376 43.73...
way/990848785     {'addr:city': 'Monaco', 'addr...  POLYGON ((7.41426 43.7339...
way/993121275      {'building': 'yes', 'name': ...  POLYGON ((7.43214 43.7481...

[7906 rows x 2 columns]

Just convert PBF to GeoParquet

>>> import quackosm as qosm
>>> gpq_path = qosm.convert_pbf_to_parquet(monaco_pbf_path)
>>> gpq_path.as_posix()
'files/monaco_nofilter_noclip_compact.parquet'

Inspect the file with duckdb

>>> import duckdb
>>> duckdb.load_extension('spatial')
>>> duckdb.read_parquet(str(gpq_path)).order("feature_id")
┌──────────────────┬──────────────────────┬──────────────────────────────────────────────┐
│    feature_id    │         tags         │                   geometry                   │
│     varchar      │ map(varchar, varch…  │                   geometry                   │
├──────────────────┼──────────────────────┼──────────────────────────────────────────────┤
│ node/10005045289 │ {shop=bakery}        │ POINT (7.4224498 43.7310532)                 │
│ node/10020887517 │ {leisure=swimming_…  │ POINT (7.4131561 43.7338391)                 │
│ node/10021298117 │ {leisure=swimming_…  │ POINT (7.4277743 43.7427669)                 │
│ node/10021298717 │ {leisure=swimming_…  │ POINT (7.4263029 43.7409734)                 │
│ node/10025656383 │ {ferry=yes, name=Q…  │ POINT (7.4254971 43.7369002)                 │
│ node/10025656390 │ {amenity=restauran…  │ POINT (7.4269287 43.7368818)                 │
│ node/10025656391 │ {name=Capitainerie…  │ POINT (7.4272127 43.7359593)                 │
│ node/10025656392 │ {name=Direction de…  │ POINT (7.4270392 43.7365262)                 │
│ node/10025656393 │ {name=IQOS, openin…  │ POINT (7.4275175 43.7373195)                 │
│ node/10025656394 │ {artist_name=Anna …  │ POINT (7.4293446 43.737448)                  │
│       ·          │          ·           │              ·                               │
│       ·          │          ·           │              ·                               │
│       ·          │          ·           │              ·                               │
│ way/986864693    │ {natural=bare_rock}  │ POLYGON ((7.4340482 43.745598, 7.4340263 4…  │
│ way/986864694    │ {barrier=wall}       │ LINESTRING (7.4327547 43.7445382, 7.432808…  │
│ way/986864695    │ {natural=bare_rock}  │ POLYGON ((7.4332994 43.7449315, 7.4332912 …  │
│ way/986864696    │ {barrier=wall}       │ LINESTRING (7.4356006 43.7464325, 7.435574…  │
│ way/986864697    │ {natural=bare_rock}  │ POLYGON ((7.4362767 43.74697, 7.4362983 43…  │
│ way/990669427    │ {amenity=shelter, …  │ POLYGON ((7.4146087 43.733883, 7.4146192 4…  │
│ way/990669428    │ {highway=secondary…  │ LINESTRING (7.4136598 43.7334433, 7.413640…  │
│ way/990669429    │ {highway=secondary…  │ LINESTRING (7.4137621 43.7334251, 7.413746…  │
│ way/990848785    │ {addr:city=Monaco,…  │ POLYGON ((7.4142551 43.7339622, 7.4143113 …  │
│ way/993121275    │ {building=yes, nam…  │ POLYGON ((7.4321416 43.7481309, 7.4321638 …  │
├──────────────────┴──────────────────────┴──────────────────────────────────────────────┤
│ 7906 rows (20 shown)                                                         3 columns │
└────────────────────────────────────────────────────────────────────────────────────────┘

Use as CLI

$ quackosm monaco.osm.pbf
⠋ [   1/32] Reading nodes • 0:00:00
⠋ [   2/32] Filtering nodes - intersection • 0:00:00
⠋ [   3/32] Filtering nodes - tags • 0:00:00
⠋ [   4/32] Calculating distinct filtered nodes ids • 0:00:00
⠋ [   5/32] Reading ways • 0:00:00
⠋ [   6/32] Unnesting ways • 0:00:00
⠋ [   7/32] Filtering ways - valid refs • 0:00:00
⠋ [   8/32] Filtering ways - intersection • 0:00:00
⠋ [   9/32] Filtering ways - tags • 0:00:00
⠋ [  10/32] Calculating distinct filtered wa

Related Skills

View on GitHub
GitHub Stars357
CategoryDevelopment
Updated3d ago
Forks17

Languages

Python

Security Score

100/100

Audited on Apr 1, 2026

No findings