Installation#
Stable Release#
Please install earthlens in a virtual environment so that its requirements don't tamper with your system's Python.
pip#
The simplest way to install earthlens is from PyPI:
That pulls in every runtime dependency. Add the backend extras you need (see Available extras) and you can skip the rest of these instructions.
conda#
earthlens is also on the conda-forge channel:
conda-forge can lag behind PyPI
The feedstock is updated separately from the PyPI release, so the conda
channel is sometimes a release or two behind — which matters, because the
public import moved to earthlens.core in 0.11.0 and 0.12.0 carried
further breaking changes (see the migration guide). Check
what the channel actually offers before relying on it:
If it is behind, install from PyPI instead.
uv#
You can also use uv to manage the environment:
Installing Python#
earthlens requires Python 3.11+.
For Python we recommend using the Anaconda Distribution for Python 3.
Install as a conda environment#
To keep earthlens isolated from other projects, create a dedicated conda environment for it:
Then activate it:
Then install a release of earthlens from PyPI. Each backend's SDK is an optional extra — pick the ones you actually need:
pip install earthlens[ecmwf] # ECMWF / Copernicus CDS
pip install earthlens[gee] # Google Earth Engine
pip install earthlens[cmems] # Copernicus Marine
pip install earthlens[all] # everything
Available extras#
Each extra pulls in exactly one backend's SDK. The names work the same whether
you install the meta-package or a thematic distribution directly:
pip install earthlens[gee] forwards to earthlens-imagery[gee].
| Extra | Provider | Pulls |
|---|---|---|
s3 |
AWS Open Data | boto3 >=1.43.0, botocore >=1.34.0 |
ecmwf |
Copernicus Climate Data Store (ECMWF) | cdsapi >=0.7.7 |
ecmwf-modern |
ECMWF (alternate SDK) | ecmwf-datastores-client >=0.5.1 |
gee |
Google Earth Engine | earthengine-api >=1.7.26, google-api-python-client >=2.0, google-cloud-storage >=2.0, Rtree >=1.0.0, urllib3 >=1.26 |
eedai |
Google Earth Engine — optional EEDAI fetch path | pyramids-eo >=0.2.0,<0.3 |
cmems |
Copernicus Marine Service | copernicusmarine >=2.0.0,<3 |
cmip6 |
WCRP CMIP6 | (none — no SDK needed) |
fdsn |
FDSN | obspy >=1.5.0 |
nwm |
NOAA National Water Model | earthlens[s3], pyramids-gis[parquet] >=0.46.0 |
earthdata |
NASA Earthdata | earthaccess >=0.18.0; python_version >= '3.12' |
asf |
Alaska Satellite Facility (ASF) | asf_search >=12.2.2, earthlens[earthdata] |
eea_aq |
European Environment Agency | airbase >=1.0, nest_asyncio >=1.5 |
hdx |
Humanitarian Data Exchange (UN OCHA) | hdx-python-api >=6,<7 |
eumetsat |
EUMETSAT | eumdac >=3.1 |
nwp |
Herbie (NWP archive access) | herbie-data >=2026.3, ecmwf-opendata >=0.3, ecmwflibs; sys_platform == 'win32' |
radar |
NOAA NEXRAD | earthlens[s3] |
dem |
Copernicus DEM (ESA) | earthlens[s3] |
goes |
NOAA GOES-R | earthlens[s3] |
stac |
STAC (SpatioTemporal Asset Catalog) | pyramids-gis[stac] >=0.46.0 |
openeo |
openEO | openeo >=0.47,<0.52 |
sentinel-hub |
Sentinel Hub | sentinelhub >=3.11.5 |
tropycal |
Tropycal | tropycal >=1.4, cartopy >=0.22 |
overture |
Overture Maps Foundation | overturemaps >=1.0.0, duckdb >=1.0.0 |
usgs-water |
USGS National Water Information System | dataretrieval >=1.1.4 |
ghsl |
European Commission Joint Research Centre (GHSL) | (none — no SDK needed) |
worldpop |
WorldPop | worldpoppy >=0.4, py7zr >=0.20 |
gbif |
GBIF | pygbif >=0.6.6 |
obis |
OBIS | pyobis >=1.6.1 |
jaxa |
JAXA | jaxa.earth >=0.1.6,<0.2, gportal >=0.4,<0.5 |
argo |
Argo Program | argopy >=1.4 |
erddap |
NOAA ERDDAP | erddapy >=3.0 |
osm |
OpenStreetMap | overpy >=0.7, ohsome >=0.4.0 |
osm-pbf |
OpenStreetMap (bulk .osm.pbf extracts) | pyrosm >=0.11.0, osmium >=4.3.1 |
all |
every backend above except argo, osm-pbf (see What earthlens[all] excludes) |
— |
A bare pip install earthlens installs only the core dependencies (numpy, pandas, pyramids-gis,
requests, …), which is enough for every backend with no extra SDK of its own: geoBoundaries, AirNow, GEBCO/ETOPO bathymetry, CHC/CHIRPS, climate teleconnection indices, USDM/EDO/GDO/SPEIbase, NASA FIRMS, GDACS, RGI/GLIMS/WGMS glaciers, IUCN Red List, NREL/National Laboratory of the Rockies, OpenAQ, PVGIS, ThinkHazard!/INFORM, Sensor.Community, SoilGrids, Global Solar/Wind Atlas, Protected Planet.
Asking the facade for a backend whose extra is missing (e.g. data_source="ecmwf" without
earthlens[ecmwf]) raises a clear ImportError naming the extra to install.
Package layout#
earthlens is a meta-package. Installing it pulls in earthlens-core plus
five thematic provider packages, each carrying a group of backends:
| Package | Covers | Backends |
|---|---|---|
earthlens-core |
facade, abstractions, CLI — no provider SDKs | — |
earthlens-atmosphere |
weather · climate · air quality · solar/wind | chc climate_indices cmip6 drought ecmwf nwp amazon-s3 airnow eea_aq openaq sensor_community goes radar tropycal nrel pvgis solar_wind_atlas |
earthlens-ocean |
ocean · freshwater · marine life | argo cmems erddap nwm usgs_water obis |
earthlens-imagery |
satellite platforms · SAR · EO catalogs | asf earthdata eumetsat gee jaxa openeo sentinel_hub stac |
earthlens-land |
terrain · elevation · soil · ecology · population | bathymetry dem ghsl glaciers gbif iucn soilgrids wdpa worldpop |
earthlens-hazards |
hazards · humanitarian · vector basemaps | fdsn firms gdacs risk_indicators admin osm overture hdx |
This changes nothing about how you use earthlens: the import path is the same
(from earthlens.core import EarthLens, earthlens.chc, …), and every extra above
works exactly as before — pip install earthlens[gee] still installs Earth
Engine and nothing else.
Installing a single domain. If you only need one group, install that package directly and skip the others' backends entirely:
pip install earthlens-imagery[gee] # Earth Engine, without the other 53 backends
pip install earthlens-ocean[argo,cmems]
pip install earthlens-atmosphere[all] # every atmosphere SDK
A thematic package depends only on earthlens-core, so its SDKs stay extras:
pip install earthlens-imagery gives you the imagery backends' code without
earthengine-api, openeo, eumdac and the rest.
Why the split. Two provider SDKs cannot coexist in one environment.
argopy (the argo extra) requires xarray>=2025.7, while openeo — which
is part of earthlens[all] — caps xarray<2025.01.2, and no single xarray
satisfies both. The root pyproject.toml declares those two extras conflicting
under [tool.uv] conflicts, so uv forks the lockfile: argopy and
openeo both live in one uv.lock on their own xarray (2025.1.1 for the
openeo / all side, 2025.9.0 for the argo side), and each side installs
cleanly on its own. Splitting the backends across packages then lets you install
one domain's dependencies without inheriting every other domain's constraints.
What earthlens[all] excludes, and why#
earthlens[all] is the union of every backend extra that can honestly share
one environment — that is every extra in the table above except three:
argo, osm-pbf and eedai. Each is left out for a concrete reason:
| Excluded | SDK | Why it can't join all |
|---|---|---|
argo |
argopy |
Two independent problems, either one disqualifying. (1) xarray — a resolution conflict: argopy >=1.4 needs xarray>=2025.7, but openeo (in all) caps xarray<2025.01.2 — disjoint ranges, which is what [tool.uv] conflicts declares. (2) erddapy — a runtime break: argopy 1.4.0 still resolves (it does not cap erddapy) but fails at import — it imports erddapy.erddapy._quote_string_constraints, which erddapy 3.3 removed — while the erddap extra (in all) requires erddapy>=3.0. |
osm-pbf |
pyrosm |
pyrosm (0.11) and osmium (4.3.1) both ship wheels, but pyrosm pulls the sdist-only cykhash (no wheels for any Python), so adding osm-pbf to all would make pip install earthlens[all] require a C compiler — it is kept out to keep all wheel-only. Tracked in #783. |
| eedai | pyramids-eo | It resolves cleanly — this one is about behaviour, not packaging. Installing it activates the GEE backend's default engine="auto", which serves raw single-asset reads through the EEDAI reader; that path samples and grids differently from Earth Engine (see the GEE usage page). Holding it out of all means an upgrade never silently changes an existing user's pixels. |
(osm itself is in all — see the resolution note below for why.)
Each still installs on its own, in a separate environment:
pip install earthlens[argo] # its own env — pulls xarray>=2025.7
pip install earthlens[osm-pbf] # builds cykhash (a pyrosm dep) from source — needs a C compiler
What an
allinstall actually resolves to. Withargoout,earthlens[all]lands on theopeneoside of the fork, andopeneo 0.51caps bothxarray<2025.01.2andpandas<3.0.0— so anallenvironment runs onxarray 2025.1.1andpandas 2.x. That pandas-2.x floor is exactly what letsosmsit inall:ohsome's ownpandas<3.0.0agrees rather than collides. Every other backend works; asking the facade for an excluded one (e.g.data_source="argo") without its extra raises a clearImportErrornaming the extra to install.Heads-up —
argois currently broken even on its own. Sinceerddapy 3.3(released 2026-06-30) a plainpip install earthlens[argo]pullserddapy 3.3, andimport argopythen fails withImportError: cannot import name '_quote_string_constraints'. This is an upstreamargopybug (euroargodev/argopy#657), tracked for earthlens in serapeum-org/earthlens#789; theargobackend will work again onceargopyships a fix.
From Sources#
The sources for earthlens can be downloaded from the GitHub repo.
Clone the public repository:
Or download the tarball:
The repository is a workspace of seven distributions, so a source install has
to install the members too — pip install -e . on its own installs the
meta-package, which then looks for earthlens-core on PyPI at the version
in the working tree, and an unreleased version is not there:
Install the whole workspace instead, naming every member on one command line so pip resolves them locally rather than from the index:
pip install -e libs/core \
-e libs/providers/atmosphere \
-e libs/providers/ocean \
-e libs/providers/imagery \
-e libs/providers/land \
-e libs/providers/hazards \
-e ".[ecmwf]"
With uv this is a single command — the members are
declared as a workspace in pyproject.toml, so one lock covers them all:
If you only want one domain from a clone, its package plus core is enough:
To install a published release directly from GitHub (its members are on PyPI, so the meta-package resolves normally):
Installing the HEAD of main this way does not work: main carries an
unreleased version whose members are not on PyPI yet, and pip cannot install a
workspace's sibling packages out of a single git URL. Clone the repository and
use the editable workspace install above.
To verify the installation, import from earthlens.core and print the version:
A bare import earthlens is not a useful check — earthlens is a PEP 420
namespace package, so that import succeeds even when nothing is installed.
Install using pip#
Install earthlens with pip, picking the backend extras you need (see Available extras for the full list):
Development install#
If you are planning to contribute to earthlens, install the whole workspace
editable with the [all] extra so the full test suite (which exercises every
backend) can run. uv is the supported path — it
installs every workspace member from one lockfile (uv.lock). --extra all
pulls every backend SDK except the two extras excluded from all
(argo / osm-pbf — see What earthlens[all] excludes):
git clone https://github.com/serapeum-org/earthlens.git
cd earthlens
uv sync --extra all --group dev
uv run pytest -m "not e2e"
The equivalent with pip, which must name every member so they resolve from the clone rather than from PyPI:
pip install -e libs/core \
-e libs/providers/atmosphere \
-e libs/providers/ocean \
-e libs/providers/imagery \
-e libs/providers/land \
-e libs/providers/hazards \
-e ".[all]"
The tests import earthlens from the installed distributions, not from the
source tree: earthlens is a PEP 420 namespace shared across all seven
distributions, and each provider's earthlens.<backend> subpackage lives in its
own source tree, reachable only through the finder an editable install sets up.
Running pytest against a clone without installing the workspace first will not
collect.
Running the tests#
Tests are co-located with the distribution they cover, under each member's
tests/ directory:
libs/core/tests/ # facade, base, CLI, grids, entry-point discovery
libs/providers/<theme>/tests/ # each theme's backend tests
# (atmosphere, ocean, imagery, land, hazards)
uv run pytest -m "not e2e" from the repo root runs the whole suite — the
root pyproject.toml lists all six member test roots in testpaths. To run (or
measure coverage for) a single distribution, point pytest at that member's
own config:
# one distribution, standalone
uv run pytest -c libs/providers/imagery/pyproject.toml libs/providers/imagery/tests -m "not e2e"
# or, equivalently, from inside the member
cd libs/providers/imagery && uv run pytest -m "not e2e"
CI mirrors this: tests.yml runs one lane per distribution
(--cov=libs/<member>/src, uploaded to Codecov under a per-member flag), so a
failure is attributed to the distribution that owns it. End-to-end tests
(-m e2e) are opt-in and run in the separate tests-e2e.yml workflow.
One coupling to note: earthlens-core's entry-point discovery and facade tests
(test_backends.py, test_earthlens.py) exercise the whole registry — they
assert every provider's backends are discoverable — so they require all five
provider distributions to be installed, which the workspace dev setup
(uv sync --extra all) always provides. A consequence is that a cross-provider
entry-point or packaging regression surfaces in the core lane, not only the
offending provider's lane.
More details on conda environments: Managing environments