openEO backend — usage#
Request shape#
EarthLens(
data_source="openeo",
variables={collection_or_recipe_key: [band, ...]},
start="YYYY-MM-DD", end="YYYY-MM-DD",
lat_lim=[lat_min, lat_max],
lon_lim=[lon_min, lon_max],
path="out",
# optional openEO kwargs:
endpoint=None, # "cdse" (default) / "cdse-federation" / "openeo-platform" / URL
process=None, # explicit recipe key, overriding the one inferred from the request key
execute="sync", # "sync" (default) or "batch"
output_format="GTiff", # "GTiff" (default) or "netCDF"
max_cloud_cover=None, # server-side property filter on load_collection (Sentinel-2)
# OIDC credential kwargs (see Authentication): client_id / client_secret / refresh_token / provider_id
)
variables maps each key to a band list. A key is either:
- a collection (e.g.
"sentinel-2-l2a") → the default graphload_collection → clip → save, loading the bands you list (or the collection'sdefault_bandswhen the list is empty); or - a recipe (e.g.
"sentinel-2-l2a-ndvi-monthly") → the recipe's fixed graph. An empty band list uses the recipe's own bands; a non-empty list overrides them.
Multiple keys per call are allowed — one output file is written per key.
Kwargs#
| Kwarg | Default | Meaning |
|---|---|---|
endpoint |
"cdse" |
which openEO backend to target (Introduction) |
process |
None |
apply this recipe to every request key, overriding the inferred recipe/collection |
execute |
"sync" |
"sync" = DataCube.download (size-capped); "batch" = a polled batch job |
output_format |
"GTiff" |
openEO output format; a recipe's own output_format wins when set |
max_cloud_cover |
None |
forwarded to load_collection(max_cloud_cover=…); only for optical collections that expose eo:cloud_cover (Sentinel-2). Passing it to a non-optical collection (SAR, atmosphere, DEM) raises ValueError. |
output_formatis named distinctly fromfmt(the date-string format inherited from the facade) on purpose — the two never collide.
Server-side aggregation (aggregate=)#
Because openEO reduces server-side, an aggregate=AggregationConfig(...)
becomes a native aggregate_temporal_period node in the graph (before
save_result) — the only backend where aggregate= costs no client compute
and no pyramids reducer.
from earthlens.aggregate import AggregationConfig
EarthLens(
data_source="openeo",
variables={"sentinel-2-l2a": ["B04", "B08"]},
start="2023-01-01", end="2023-12-31",
lat_lim=[40.40, 40.45], lon_lim=[3.67, 3.72],
path="out",
).download(aggregate=AggregationConfig(freq="1MS", op="mean"))
The aggregator's pandas freq is mapped to an openEO calendar period, and
its op to an openEO reducer:
AggregationConfig.freq |
openEO period |
AggregationConfig.op |
openEO reducer |
|
|---|---|---|---|---|
D / 7D |
day |
auto |
mean |
|
W |
week |
mean |
mean |
|
10D |
dekad (10-day) |
sum |
sum |
|
MS / M |
month |
min / max |
min / max |
|
QS / Q |
season |
std |
sd |
|
YS / Y |
year |
A freq with no calendar equivalent raises NotImplementedError naming the
supported periods.
Execution: sync vs batch#
execute="sync"(default) —DataCube.download(path, format=…). Fast, but the openEO sync endpoint has size/time caps; use it for small AOIs and short windows.execute="batch"—cube.create_job().start_and_wait().get_results() .download_file(path). The backend submits a batch job and polls to completion, like GEE's async export. Use it for large AOIs / long windows.
EarthLens(
data_source="openeo",
variables={"sentinel-2-l2a-cloud-masked-composite": []},
start="2023-06-01", end="2023-08-31",
lat_lim=[40.0, 41.0], lon_lim=[3.0, 4.0],
path="out",
execute="batch",
).download()
Return value#
download() returns a list[pathlib.Path] — one written file per request key.
The suffix follows the format (.tif for GTiff, .nc for netCDF); a
recipe's output_format overrides the backend default.
Catalog tooling#
Three scripts under tools/openeo/ (the same refresh / probe / audit set
the other backends ship). Listing and describing are anonymous — no OIDC
login is needed for any of them.
refresh_openeo_catalog.py — keep the informational index current and
validate a recipe:
# Rebuild available_collections / available_processes in _index.yaml:
python tools/openeo/refresh_openeo_catalog.py refresh
# Print the regenerated index without writing it:
python tools/openeo/refresh_openeo_catalog.py refresh --dry-run
# Check a recipe's base collection + process names exist on the backend:
python tools/openeo/refresh_openeo_catalog.py validate-recipe sentinel-2-l2a-ndvi-monthly
audit_openeo_datasets.py — diff the curated catalog against the live
backend (curated collections no longer served, recipe processes no longer
advertised, untracked live collections):
python tools/openeo/audit_openeo_datasets.py audit
python tools/openeo/audit_openeo_datasets.py audit --strict # exit 1 on any drift
earthlens datasets probe openeo <id> — inspect one collection's live
metadata when curating a new row: the band schema plus one dim:<axis> row
per non-band cube axis (the spatial bbox / temporal interval):
earthlens datasets probe openeo SENTINEL2_L2A
earthlens datasets probe openeo ESA_WORLDCOVER_10M_2021_V2 --json
validate-recipe and audit --strict exit non-zero on any drift (a base
collection or a process the backend no longer advertises).
Gotchas & limits#
- Sync size cap — large requests fail the sync endpoint; switch to
execute="batch". - OIDC in CI — the interactive flow needs a browser once; CI must use client-credentials or a cached refresh token (see Authentication).
- Recipe bands — overriding a recipe's bands can break its graph (e.g. the
NDVI recipe needs
B04/B08/SCL); prefer leaving the band list empty. - MVP scope — arbitrary user-supplied process graphs / UDFs are a follow-on; the MVP ships the curated recipe library plus plain-collection loads.