Skip to main content

tabular-py

Python reader for dclimate-tabular/0 — content-addressed station/telemetry data on IPFS.

The Python counterpart to tabular-js, reading the same format from the same CIDs. Built on py-hamt, which supplies the HAMT and the content-addressed store the same way @dclimate/ipld-index does for JS.

tabular-js  ->  @dclimate/ipld-index      (HAMT, CAS, range reads)
tabular-py  ->  py-hamt                   (same, already existed)

Status

Reader only. Publishing, compaction, and rollup stay in tabular-js — the ETL that writes these datasets is JS, and a second writer would be a second thing to keep byte-identical for no current gain. Everything needed to read a dataset published by tabular-js is here.

Install

uv pip install dclimate-tabular-py

Usage

import asyncio
from tabular_py import GatewayRangeSource, StationDataset

async def main():
    source = GatewayRangeSource("https://ipfs-gateway.dclimate.net")
    ds = await StationDataset.open(source, "bafyr4if2wbttslbxpzmro427j4l4nvcrxqo4tufuffqqmqz7afj2pxyu4a")

    # nearest station to a point, then a year of readings
    near = await ds.nearest(34.05, -118.24, max_km=100)
    rows = await near.time_range("2024-01-01", "2024-12-31").elements("PRCP").rows()
    for row in rows[:5]:
        print(row.station_id, row.ts, row.values)

asyncio.run(main())

The chainable selection API mirrors tabular-js:

ds.select("USW00023174")           # explicit station ids
ds.circle(34.05, -118.24, 50)      # within 50 km
ds.rectangle(33.0, -119.0, 35.0, -117.0)
ds.polygon([[(lon, lat), ...]])
await ds.nearest(lat, lon)         # async: reads the geo index
ds.time_range(start, end)
ds.elements("PRCP", "TMAX")
ds.where(gt("TMAX", 300))          # pushed down to fragment statistics

Selections are immutable — each call returns a new StationDataset, so a base dataset can be reused across queries.

Terminal operations:

Call Returns
await ds.rows() list[ResultRow]
await ds.to_records() list[dict]station_id, time, values
await ds.to_records("TMAX") list[dict]station_id, time, value
await ds.to_arrow() pyarrow.Table
await ds.plan() QueryPlan — what would be fetched, without fetching
await ds.list_stations() list[StationInfo]

How reads stay small

A query never scans the dataset. Three things prune before any Parquet byte is fetched:

  1. The station index (a HAMT keyed by station id) resolves named stations directly.
  2. The geo projection answers region queries by reading one or two shard blocks instead of walking all 132k stations.
  3. Fragment statistics in the manifest — per-column min/max and null counts — let a predicate skip whole fragments unread.

What survives is fetched with HTTP range requests against the exact column-chunk byte ranges the manifest records, so a query for one column of one year moves kilobytes.

One deviation from tabular-js, and why

tabular-js synthesizes Parquet FileMetaData client-side from the manifest and reads a fragment with zero footer fetches. PyArrow exposes no public FileMetaData constructor, so that trick does not transfer.

Instead this reader fetches the footer by its manifest-recorded footer_offset/footer_length in a single ranged GET, verifies it against the manifest's footer_digest, and hands the parsed metadata to PyArrow. Cost is one extra range request per fragment — and it buys a corruption check tabular-js does not perform. Footers are cached per fragment CID, so a repeated query pays it once.

Development

uv sync
uv run pytest                     # unit tests, no network
uv run pytest -m network          # conformance against the live gateway
uv run ruff check . && uv run mypy tabular_py

tests/test_conformance.py reads a real published GHCNd dataset (bafyr4if2wbttslbxpzmro427j4l4nvcrxqo4tufuffqqmqz7afj2pxyu4a, 132,437 stations, 1.15 B rows) and asserts this implementation agrees with tabular-js on decoded values.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dclimate_tabular_py-0.1.0.tar.gz (354.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dclimate_tabular_py-0.1.0-py3-none-any.whl (47.8 kB view details)

Uploaded Python 3

File details

Details for the file dclimate_tabular_py-0.1.0.tar.gz.

File metadata

  • Download URL: dclimate_tabular_py-0.1.0.tar.gz
  • Upload date:
  • Size: 354.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.8

File hashes

Hashes for dclimate_tabular_py-0.1.0.tar.gz
Algorithm Hash digest
SHA256 930e94f13da793bf5dc317166d33f17b39253dcf81d19898d34269321d28faff
MD5 847ce1246ac6dfbede3cba46166bb1aa
BLAKE2b-256 fecca409e8a1399679cb3798b9276519a673380c62f6f448416189513baaddf6

See more details on using hashes here.

File details

Details for the file dclimate_tabular_py-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for dclimate_tabular_py-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b78c55c89fc92302126794487462f6407c9e496aa140945dc12eafe6adb5e052
MD5 84ae297acdbcc18a428e251add94033e
BLAKE2b-256 377578448edafb885c249540d96e3c28b3b886bf320f153d2c2b5342e6408118

See more details on using hashes here.

Release history Release notifications | RSS feed

0.3.1

2 files

0.3.0

2 files

0.2.1

2 files

0.2.0

2 files

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page