Skip to content

Core functions#

The module-level surface of earthlens.core — one-shot helpers that wrap the EarthLens facade, plus the discovery functions for finding a dataset across all 61 providers.

from earthlens.core import download, find, search, sources

For a task-oriented walkthrough of find / search / sources, see Discovering datasets.

download#

The one-shot equivalent of constructing an EarthLens and calling .download(). Takes the same arguments as the facade constructor and returns the backend's result directly.

earthlens.core.download(data_source='chc', *, variables=None, dataset=None, start=None, end=None, path=None, lat_lim=None, lon_lim=None, aoi=None, buffer=None, temporal_resolution='daily', cadence=None, time=None, fmt='%Y-%m-%d', progress_bar=True, aggregate=None, load=False, **backend_kwargs) #

Construct an :class:EarthLens and download in one call.

The one-shot convenience for the common case: it forwards every request argument to :class:EarthLens and the run-time arguments to :meth:EarthLens.download, so earthlens.core.download(...) replaces the two-step construct-then-download.

Parameters:

Name Type Description Default
data_source str

Backend key (see sorted(EarthLens.DataSources)). Defaults to "chc".

'chc'
variables dict[str, list[str]] | list[str] | None

Variable specification, as for :class:EarthLens.

None
dataset str | None

Explicit dataset / collection key (see :class:EarthLens).

None
start str | datetime | date | None

Inclusive start date (string / datetime / date).

None
end str | datetime | date | None

Inclusive end date.

None
time Any

A single time range ("a/b" string / (a, b) pair / slice / single date) — the ergonomic alternative to start / end; mutually exclusive with them.

None
path Path | str | None

Output directory; defaults to <output_dir()>/<data_source>/ when omitted — the directory configured by set_output_dir() / EARTHLENS_DATA_DIR.

None
lat_lim list[float] | None

Legacy [lat_min, lat_max] pair — prefer aoi= (mutually exclusive with it).

None
lon_lim list[float] | None

Legacy [lon_min, lon_max] pair — prefer aoi= (mutually exclusive with it).

None
aoi Any

A single area-of-interest (bbox / point+buffer / geometry).

None
buffer float | None

Half-width in degrees for a point aoi.

None
temporal_resolution str

Backend cadence / label. Defaults to "daily".

'daily'
cadence str | None

Clearer alias for temporal_resolution (overrides it when given). Defaults to None.

None
fmt str

strptime format override for string dates.

'%Y-%m-%d'
progress_bar bool

Whether the backend prints a progress bar.

True
aggregate AggregationConfig | None

Optional :class:~earthlens.aggregate.AggregationConfig.

None
load bool

When True, return the data in memory via :meth:EarthLens.load (written rasters read into pyramids Dataset / NetCDF objects) instead of the written paths. Defaults to False.

False
**backend_kwargs object

Extra backend-specific options (see :meth:EarthLens.options_for).

{}

Returns:

Name Type Description
Whatever Any

meth:EarthLens.download returns for the backend, or —

Any

when load=True — the in-memory objects from :meth:EarthLens.load.

Examples:

  • One-shot CHIRPS download. Marked # doctest: +SKIP because it makes a live FTP connection:
    >>> import earthlens.core
    >>> earthlens.core.download(  # doctest: +SKIP
    ...     data_source="chc",
    ...     variables=["precipitation"],
    ...     start="2009-01-01", end="2009-01-02",
    ...     aoi=[-75.65, 4.19, -74.73, 4.64],
    ...     path="examples/data/chirps",
    ... )
    
Source code in libs/core/src/earthlens/earthlens.py
def download(
    data_source: str = "chc",
    *,
    variables: dict[str, list[str]] | list[str] | None = None,
    dataset: str | None = None,
    start: str | datetime | date | None = None,
    end: str | datetime | date | None = None,
    path: Path | str | None = None,
    lat_lim: list[float] | None = None,
    lon_lim: list[float] | None = None,
    aoi: Any = None,
    buffer: float | None = None,
    temporal_resolution: str = "daily",
    cadence: str | None = None,
    time: Any = None,
    fmt: str = "%Y-%m-%d",
    progress_bar: bool = True,
    aggregate: AggregationConfig | None = None,
    load: bool = False,
    **backend_kwargs: object,
) -> Any:
    """Construct an :class:`EarthLens` and download in one call.

    The one-shot convenience for the common case: it forwards every
    request argument to :class:`EarthLens` and the run-time arguments to
    :meth:`EarthLens.download`, so `earthlens.core.download(...)` replaces the
    two-step construct-then-download.

    Args:
        data_source: Backend key (see `sorted(EarthLens.DataSources)`).
            Defaults to `"chc"`.
        variables: Variable specification, as for :class:`EarthLens`.
        dataset: Explicit dataset / collection key (see
            :class:`EarthLens`).
        start: Inclusive start date (string / `datetime` / `date`).
        end: Inclusive end date.
        time: A single time range (`"a/b"` string / `(a, b)` pair / `slice` /
            single date) — the ergonomic alternative to `start` / `end`;
            mutually exclusive with them.
        path: Output directory; defaults to
            `<output_dir()>/<data_source>/` when omitted — the directory
            configured by `set_output_dir()` / `EARTHLENS_DATA_DIR`.
        lat_lim: Legacy `[lat_min, lat_max]` pair — prefer `aoi=` (mutually
            exclusive with it).
        lon_lim: Legacy `[lon_min, lon_max]` pair — prefer `aoi=` (mutually
            exclusive with it).
        aoi: A single area-of-interest (bbox / point+`buffer` / geometry).
        buffer: Half-width in degrees for a point `aoi`.
        temporal_resolution: Backend cadence / label. Defaults to
            `"daily"`.
        cadence: Clearer alias for `temporal_resolution` (overrides it
            when given). Defaults to `None`.
        fmt: `strptime` format override for string dates.
        progress_bar: Whether the backend prints a progress bar.
        aggregate: Optional :class:`~earthlens.aggregate.AggregationConfig`.
        load: When `True`, return the data in memory via
            :meth:`EarthLens.load` (written rasters read into pyramids
            `Dataset` / `NetCDF` objects) instead of the written paths.
            Defaults to `False`.
        **backend_kwargs: Extra backend-specific options (see
            :meth:`EarthLens.options_for`).

    Returns:
        Whatever :meth:`EarthLens.download` returns for the backend, or —
        when `load=True` — the in-memory objects from :meth:`EarthLens.load`.

    Examples:
        - One-shot CHIRPS download. Marked `# doctest: +SKIP` because it
          makes a live FTP connection:
            ```python
            >>> import earthlens.core
            >>> earthlens.core.download(  # doctest: +SKIP
            ...     data_source="chc",
            ...     variables=["precipitation"],
            ...     start="2009-01-01", end="2009-01-02",
            ...     aoi=[-75.65, 4.19, -74.73, 4.64],
            ...     path="examples/data/chirps",
            ... )

            ```
    """
    facade = EarthLens(
        data_source=data_source,
        variables=variables,
        dataset=dataset,
        start=start,
        end=end,
        path=path,
        lat_lim=lat_lim,
        lon_lim=lon_lim,
        aoi=aoi,
        buffer=buffer,
        temporal_resolution=temporal_resolution,
        cadence=cadence,
        time=time,
        fmt=fmt,
        **backend_kwargs,
    )
    if load:
        return facade.load(progress_bar=progress_bar, aggregate=aggregate)
    return facade.download(progress_bar=progress_bar, aggregate=aggregate)

sources#

earthlens.core.sources() #

Return the sorted list of distinct backends, one canonical key each.

The top-level discovery entry point — no class needed to see what backends earthlens.core.download(...) / :class:EarthLens accept. Alias and endpoint keys ("chirps" for "chc", "google-earth-engine" for "gee", the STAC endpoint keys "planetary-computer" / "earth-search" / "cdse", …) still work as data_source= values but are collapsed to their canonical backend key here, so the list is one entry per backend.

Returns:

Type Description
list[str]

The canonical data_source key of each registered backend, sorted.

Examples:

  • The CHIRPS and GEE backends are listed by their canonical keys:
    >>> import earthlens.core
    >>> keys = earthlens.core.sources()
    >>> "chc" in keys and "gee" in keys
    True
    
  • Aliases are collapsed, so each backend appears once:
    >>> import earthlens.core
    >>> keys = earthlens.core.sources()
    >>> "chirps" in keys or "google-earth-engine" in keys
    False
    
Source code in libs/core/src/earthlens/earthlens.py
def sources() -> list[str]:
    """Return the sorted list of distinct backends, one canonical key each.

    The top-level discovery entry point — no class needed to see what
    backends `earthlens.core.download(...)` / :class:`EarthLens` accept. Alias and
    endpoint keys (`"chirps"` for `"chc"`, `"google-earth-engine"` for
    `"gee"`, the STAC endpoint keys `"planetary-computer"` / `"earth-search"`
    / `"cdse"`, …) still work as `data_source=` values but are collapsed to
    their canonical backend key here, so the list is one entry per backend.

    Returns:
        The canonical `data_source` key of each registered backend, sorted.

    Examples:
        - The CHIRPS and GEE backends are listed by their canonical keys:
            ```python
            >>> import earthlens.core
            >>> keys = earthlens.core.sources()
            >>> "chc" in keys and "gee" in keys
            True

            ```
        - Aliases are collapsed, so each backend appears once:
            ```python
            >>> import earthlens.core
            >>> keys = earthlens.core.sources()
            >>> "chirps" in keys or "google-earth-engine" in keys
            False

            ```
    """
    seen_modules: set[str] = set()
    canonical: list[str] = []
    for key, module, _extras in EarthLens.DataSources.entries():
        if module not in seen_modules:
            seen_modules.add(module)
            canonical.append(key)
    return sorted(canonical)

find#

earthlens.core.find(text) #

Find which sources expose a dataset matching text.

A best-effort, cross-source discovery aid: it runs :meth:EarthLens.guess_dataset (case-insensitive substring, then fuzzy) against every registered source and collects the hits. A source whose SDK is not installed, or that has no free-text catalog, is skipped rather than failing the whole call — so the result covers the installed backends.

Parameters:

Name Type Description Default
text str

Free-text dataset query, e.g. "precipitation" or "era5".

required

Returns:

Type Description
dict[str, list[str]]

A mapping {data_source: [matching dataset key, ...]} for every

dict[str, list[str]]

source with at least one match, in sorted-source order.

Examples:

  • Find sources whose catalog mentions precipitation (live; skipped):
    >>> import earthlens.core
    >>> earthlens.core.find("precipitation")  # doctest: +SKIP
    {'chc': ['global-daily', ...], ...}
    
Source code in libs/core/src/earthlens/earthlens.py
def find(text: str) -> dict[str, list[str]]:
    """Find which sources expose a dataset matching `text`.

    A best-effort, cross-source discovery aid: it runs
    :meth:`EarthLens.guess_dataset` (case-insensitive substring, then fuzzy)
    against every registered source and collects the hits. A source whose SDK
    is not installed, or that has no free-text catalog, is skipped rather than
    failing the whole call — so the result covers the installed backends.

    Args:
        text: Free-text dataset query, e.g. `"precipitation"` or `"era5"`.

    Returns:
        A mapping `{data_source: [matching dataset key, ...]}` for every
        source with at least one match, in sorted-source order.

    Examples:
        - Find sources whose catalog mentions precipitation (live; skipped):
            ```python
            >>> import earthlens.core
            >>> earthlens.core.find("precipitation")  # doctest: +SKIP
            {'chc': ['global-daily', ...], ...}

            ```
    """
    matches: dict[str, list[str]] = {}
    for source in sources():
        try:
            hits = EarthLens.guess_dataset(source, text)
        except Exception as exc:  # noqa: BLE001 - skip uninstalled / catalog-less backends
            # Log (rather than silently drop) so a real `guess_dataset`
            # bug is traceable instead of just under-reporting.
            logger.debug(f"find(): skipping {source!r}: {type(exc).__name__}: {exc}")
            continue
        if hits:
            matches[source] = hits
    return matches

earthlens.core.search(data_source='chc', *, variables=None, dataset=None, start=None, end=None, path=None, lat_lim=None, lon_lim=None, aoi=None, buffer=None, temporal_resolution='daily', cadence=None, time=None, fmt='%Y-%m-%d', **backend_kwargs) #

Construct an :class:EarthLens and run a dry-run search in one call.

The one-shot counterpart to :func:download for the search→fetch split: it forwards every request argument to :class:EarthLens and returns :meth:EarthLens.search — the products a download would fetch — without downloading anything.

Parameters:

Name Type Description Default
data_source str

Backend key (see :func:sources). Defaults to "chc".

'chc'
variables dict[str, list[str]] | list[str] | None

Variable specification, as for :class:EarthLens.

None
dataset str | None

Explicit dataset / collection key.

None
start str | datetime | date | None

Inclusive start date (string / datetime / date).

None
end str | datetime | date | None

Inclusive end date.

None
time Any

A single time range ("a/b" string / (a, b) pair / slice / single date) — the ergonomic alternative to start / end; mutually exclusive with them.

None
path Path | str | None

Output directory (unused by a dry-run search, but accepted for signature parity with :func:download).

None
lat_lim list[float] | None

Legacy [lat_min, lat_max] pair — prefer aoi= (mutually exclusive with it).

None
lon_lim list[float] | None

Legacy [lon_min, lon_max] pair — prefer aoi= (mutually exclusive with it).

None
aoi Any

A single area-of-interest (bbox / point+buffer / geometry).

None
buffer float | None

Half-width in degrees for a point aoi.

None
temporal_resolution str

Backend cadence / label. Defaults to "daily".

'daily'
cadence str | None

Clearer alias for temporal_resolution.

None
fmt str

strptime format override for string dates.

'%Y-%m-%d'
**backend_kwargs object

Extra backend-specific options.

{}

Returns:

Name Type Description
One list[RemoteProduct]

class:~earthlens.base.RemoteProduct per matching item.

Raises:

Type Description
NotImplementedError

If the backend exposes no searchable product list (see :meth:EarthLens.search).

Examples:

  • Dry-run a STAC search and inspect the first product id (live; skipped here because it queries a remote catalog):
    >>> import earthlens.core
    >>> products = earthlens.core.search(  # doctest: +SKIP
    ...     "stac",
    ...     dataset="sentinel-2-l2a",
    ...     variables=["red"],
    ...     start="2020-06-01", end="2020-06-30",
    ...     aoi=[-75, 4, -74, 5],
    ... )
    >>> products[0].id  # doctest: +SKIP
    
Source code in libs/core/src/earthlens/earthlens.py
def search(
    data_source: str = "chc",
    *,
    variables: dict[str, list[str]] | list[str] | None = None,
    dataset: str | None = None,
    start: str | datetime | date | None = None,
    end: str | datetime | date | None = None,
    path: Path | str | None = None,
    lat_lim: list[float] | None = None,
    lon_lim: list[float] | None = None,
    aoi: Any = None,
    buffer: float | None = None,
    temporal_resolution: str = "daily",
    cadence: str | None = None,
    time: Any = None,
    fmt: str = "%Y-%m-%d",
    **backend_kwargs: object,
) -> list[RemoteProduct]:
    """Construct an :class:`EarthLens` and run a dry-run `search` in one call.

    The one-shot counterpart to :func:`download` for the search→fetch split:
    it forwards every request argument to :class:`EarthLens` and returns
    :meth:`EarthLens.search` — the products a download *would* fetch — without
    downloading anything.

    Args:
        data_source: Backend key (see :func:`sources`). Defaults to `"chc"`.
        variables: Variable specification, as for :class:`EarthLens`.
        dataset: Explicit dataset / collection key.
        start: Inclusive start date (string / `datetime` / `date`).
        end: Inclusive end date.
        time: A single time range (`"a/b"` string / `(a, b)` pair / `slice` /
            single date) — the ergonomic alternative to `start` / `end`;
            mutually exclusive with them.
        path: Output directory (unused by a dry-run search, but accepted for
            signature parity with :func:`download`).
        lat_lim: Legacy `[lat_min, lat_max]` pair — prefer `aoi=` (mutually
            exclusive with it).
        lon_lim: Legacy `[lon_min, lon_max]` pair — prefer `aoi=` (mutually
            exclusive with it).
        aoi: A single area-of-interest (bbox / point+`buffer` / geometry).
        buffer: Half-width in degrees for a point `aoi`.
        temporal_resolution: Backend cadence / label. Defaults to `"daily"`.
        cadence: Clearer alias for `temporal_resolution`.
        fmt: `strptime` format override for string dates.
        **backend_kwargs: Extra backend-specific options.

    Returns:
        One :class:`~earthlens.base.RemoteProduct` per matching item.

    Raises:
        NotImplementedError: If the backend exposes no searchable product
            list (see :meth:`EarthLens.search`).

    Examples:
        - Dry-run a STAC search and inspect the first product id (live;
          skipped here because it queries a remote catalog):
            ```python
            >>> import earthlens.core
            >>> products = earthlens.core.search(  # doctest: +SKIP
            ...     "stac",
            ...     dataset="sentinel-2-l2a",
            ...     variables=["red"],
            ...     start="2020-06-01", end="2020-06-30",
            ...     aoi=[-75, 4, -74, 5],
            ... )
            >>> products[0].id  # doctest: +SKIP

            ```
    """
    return EarthLens(
        data_source=data_source,
        variables=variables,
        dataset=dataset,
        start=start,
        end=end,
        path=path,
        lat_lim=lat_lim,
        lon_lim=lon_lim,
        aoi=aoi,
        buffer=buffer,
        temporal_resolution=temporal_resolution,
        cadence=cadence,
        time=time,
        fmt=fmt,
        **backend_kwargs,
    ).search()