Skip to main content

Generic OGC API-EDR 1.1 xarray backend

Project description

edr-xarray

Lazy xarray backend for OGC API - Environmental Data Retrieval (EDR) 1.1 /cubes endpoint.

Status: alpha (v0.1.2)

Overview

edr-xarray registers engine="edr" with xarray, letting you open any EDR 1.1-compliant collection as a lazy xarray.Dataset. Data is only fetched from the server when you call .values, .load(), or .compute() on a DataArray — opening the dataset issues lightweight metadata requests for the collection, for the selected instance when instance= is supplied, and optionally one axis-discovery probe.

Designed to be subclassed: downstream packages can override transport, metadata parsing, CoverageJSON handling, and URL routing via seven documented hook methods on EdrDataStore.

Installation

pip install edr-xarray

Or with uv:

uv add edr-xarray

Requires Python 3.11 or 3.12 and xarray 2024.6+.

Usage

import xarray as xr

# Open an EDR collection (lazy — metadata plus an optional axis probe on open)
ds = xr.open_dataset(
    "https://edr.example.com/collections/temperature_2m",
    engine="edr",
    parameter_names=["t2m"],
    bbox=(-3.5, 50.2, -2.1, 51.0),
    datetime="2023-01-01T00:00:00Z/2023-01-07T00:00:00Z",
)

# Inspect structure (no data fetched yet)
print(ds.dims)      # {'t': 168, 'y': 50, 'x': 50}
print(ds.data_vars) # {'t2m': <xarray.Variable>}
print(ds["t2m"].attrs)  # {'units': 'K', 'long_name': 'Air temperature', ...}

# Fetch a subset (triggers one EDR /cube query)
sub = ds["t2m"].sel(x=slice(-3.0, -2.5)).load()
print(sub.shape)   # (168, 50, N)

Discovery modes

By default (discovery="probe"), open_dataset issues one extra GET request to the cube endpoint to discover the exact grid axes (resolution, coordinate arrays). Two alternative modes:

When bbox=, datetime=, or z= are supplied, probe discovery uses those open-time subsets to declare xarray coordinates. For collections with long time axes and abbreviated temporal metadata, pass a bounded datetime interval so ds.t matches the analysis window. If the server advertises explicit temporal values, those values are used for the time coordinate. If it only advertises a temporal interval and no datetime= is supplied, edr-xarray opens the first instant as a small, consistent default.

# metadata_only: use only selected collection/instance metadata (bbox + temporal extent)
# Fewer requests but lower resolution coordinate arrays
ds = xr.open_dataset(url, engine="edr", discovery="metadata_only")

# strict: requires explicit temporal/vertical coordinate values in metadata
# and uses spatial bbox endpoints for x/y axes
ds = xr.open_dataset(url, engine="edr", discovery="strict")

Collections with instances (forecast runs)

When instance= is supplied, edr-xarray fetches the selected instance metadata and builds coordinates, variables, attributes, fallback bbox, and fallback datetime from that instance. Data values are still lazy and are fetched only when xarray requests concrete array values.

ds = xr.open_dataset(
    "https://edr.example.com/collections/model_output",
    engine="edr",
    instance="f024",
    parameter_names=["temperature"],
)

Vertical levels (z)

# Single level
ds = xr.open_dataset(url, engine="edr", z=850)

# Level range
ds = xr.open_dataset(url, engine="edr", z="1000/500")

Authentication

Pass a pre-configured httpx.Client for any auth style (API key, Bearer token, Basic, mTLS):

import httpx
import xarray as xr

client = httpx.Client(headers={"X-Api-Key": "your-key-here"})
ds = xr.open_dataset(url, engine="edr", session=client)

The injected client is not closed by edr-xarray — manage its lifecycle yourself.

Dask integration

Install the optional Dask extra before opening datasets with chunks=...:

pip install "edr-xarray[dask]"
# Chunk along time for out-of-core analysis
ds = xr.open_dataset(url, engine="edr", chunks={"t": 1})
result = ds["t2m"].mean(dim="t").compute()

Subclassing

Override EdrDataStore hooks to customize transport, URL routing, or response parsing:

from typing import Any, Mapping
import httpx
from edr_xarray import EdrDataStore

class AuthenticatedStore(EdrDataStore):
    def _request(
        self, method: str, url: str, *,
        params: Mapping[str, str] | None = None,
        headers: Mapping[str, str] | None = None,
    ) -> httpx.Response:
        merged = dict(headers or {})
        merged["X-Api-Key"] = "my-secret"
        return super()._request(method, url, params=params, headers=merged)

Available hooks: _request, _parse_collection_metadata, _negotiate_output_format, _build_cube_url, _parse_coveragejson, _translate_indexer, _discover_axes.

See tests/test_subclass_extensibility.py for full usage examples.

Examples

Guided Jupyter notebooks live in examples/. They use live EDR endpoints and make the lazy open, indexing, and fetch boundaries explicit.

Limitations (v1)

  • Only /cubes queries are supported (no /position, /area, /trajectory, etc.).
  • Only CoverageJSON responses (Grid domain, flat NdArray values).
  • bbox input uses CRS84 axis order (lon_min, lat_min, lon_max, lat_max).
  • No antimeridian-crossing bbox support.
  • No exotic z syntax (R14/.../..., comma-separated level lists).
  • No automatic retry, caching, or async HTTP client.

Development

git clone https://github.com/armagankaratosun/edr-xarray
cd edr-xarray
uv sync
uv run pytest

Run type checks and lint:

uv run ruff check src tests
uv run ruff format --check src tests
uv run mypy --strict src/edr_xarray
uv run pyright
uv run pyright --verifytypes edr_xarray --ignoreexternal
uv run pytest --cov=src/edr_xarray --cov-fail-under=95 -v -m "not live"

Run opt-in live tests against an EDR server:

EDR_LIVE_URL=http://localhost:8000 uv run pytest -m live

License

Apache-2.0

Project details


Download files

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

Source Distribution

edr_xarray-0.1.2.tar.gz (62.5 kB view details)

Uploaded Source

Built Distribution

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

edr_xarray-0.1.2-py3-none-any.whl (32.5 kB view details)

Uploaded Python 3

File details

Details for the file edr_xarray-0.1.2.tar.gz.

File metadata

  • Download URL: edr_xarray-0.1.2.tar.gz
  • Upload date:
  • Size: 62.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for edr_xarray-0.1.2.tar.gz
Algorithm Hash digest
SHA256 d18d249dfefad2342836b8d6d225458da10aaf549dfc7d9d370a6acc0e010c0a
MD5 fbae60ca75103be9a78c2564dca7488d
BLAKE2b-256 35245639337c32afcb08a65a040970cda53e96b3753ecc060636eba1ffe524c0

See more details on using hashes here.

Provenance

The following attestation bundles were made for edr_xarray-0.1.2.tar.gz:

Publisher: publish.yml on armagankaratosun/edr-xarray

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file edr_xarray-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: edr_xarray-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 32.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for edr_xarray-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 496ac1fe6ade30d01bea0aba202adfe2eb5a0e0a314d6786ee721d72a07ef1d3
MD5 9598d480d55a48f6cde0c55520817ff0
BLAKE2b-256 7a08ecd6161d0b3632e3c700200ccba45967bc28e90716667f5d71d9fd07232c

See more details on using hashes here.

Provenance

The following attestation bundles were made for edr_xarray-0.1.2-py3-none-any.whl:

Publisher: publish.yml on armagankaratosun/edr-xarray

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page