Python client for the Copernicus Data Space Ecosystem (CDSE) APIs
Project description
cdse
A Python client and command line tool for the Copernicus Data Space Ecosystem (CDSE) APIs.
cdse focuses on searching for and downloading Earth observation data. It wraps
the CDSE APIs behind a single authenticated client with automatic token refresh,
retries, rate limit handling, and typed responses.
Features
- OAuth2 authentication with automatic access token refresh, supporting the password, refresh token, and client credentials grants.
- A resilient HTTP layer with retries, backoff that honours
Retry-After, a proactive rate limiter, and a download concurrency limit. - OData catalogue: product search with a fluent filter builder, single product retrieval, counting, bulk name resolution, product and per file download, node tree browsing, deleted products, and attribute discovery.
- STAC catalogue: search with CQL2 filters, collection and item browse, queryables, and asset download.
- S3 direct download from the
eodataarchive (optional extra). - Sentinel-1 SLC Bursts search.
- Subscriptions for notifications about new, modified, or deleted products.
- Traceability record lookup.
- A
cdsecommand line interface covering authentication, search, and download.
Installation
pip install cdse
Optional extras:
pip install 'cdse[cli]' # the cdse command line tool
pip install 'cdse[s3]' # direct S3 archive download
pip install 'cdse[cli,s3]'
cdse requires Python 3.12 or newer.
Authentication
Most APIs require a Copernicus Data Space Ecosystem account. The client authenticates with your username and password and then refreshes the access token automatically.
from cdse import Client, PasswordAuth
# The client is a context manager; it closes its connection pool on exit.
with Client(PasswordAuth("you@example.com", "your-password")) as client:
count = client.odata.products.count()
print(f"{count} products in the catalogue")
If your account uses two factor authentication, pass the current code as
PasswordAuth("you@example.com", "pw", totp="123456"). Credentials can also be
supplied through the environment variables CDSE_USERNAME and CDSE_PASSWORD,
which the command line tool reads automatically.
Quick start: search and download with OData
from cdse import Client, PasswordAuth, FilterBuilder
with Client(PasswordAuth("you@example.com", "your-password")) as client:
query = (
FilterBuilder()
.collection("SENTINEL-2")
.acquired_between("2024-05-01", "2024-05-08")
.attribute("cloudCover", "le", 20.0)
.intersects("POLYGON((4 50, 5 50, 5 51, 4 51, 4 50))")
)
products = list(client.odata.products.search(query, top=10))
for product in products:
print(product.id, product.name)
# Download the first product as a zip archive.
client.odata.products.download(products[0].id, "product.zip", resume=True)
Browse the files inside a product and download a single one:
nodes = client.odata.products.list_nodes(products[0].id)
client.odata.products.download_node(
products[0].id, "MTD_MSIL2A.xml", destination="MTD_MSIL2A.xml"
)
Search and download with STAC
from cdse import Client, PasswordAuth
with Client(PasswordAuth("you@example.com", "your-password")) as client:
items = list(
client.stac.search(
collections=["sentinel-2-l2a"],
bbox=[4.0, 50.0, 5.0, 51.0],
datetime="2024-05-01/2024-05-08",
filter={"op": "<=", "args": [{"property": "eo:cloud_cover"}, 20]},
filter_lang="cql2-json",
)
)
item = items[0]
client.stac.download_asset(item, "PRODUCT", "product.zip")
Direct S3 download
Generate S3 credentials at
the S3 keys manager and
provide them through CDSE_S3_ACCESS_KEY and CDSE_S3_SECRET_KEY, or directly:
from cdse import S3Client
s3 = S3Client("access-key", "secret-key")
# Accepts an s3:// URI, an OData S3Path, or a bucket relative key.
s3.download("/eodata/Sentinel-2/MSI/L2A/2024/05/01/PRODUCT.SAFE/", "out/")
Sentinel-1 SLC bursts
bursts = list(
client.odata.bursts.search(swath="IW1", polarisation="VH", parent_product_id="...")
)
There is no per burst download endpoint; download the parent product with
client.odata.products.download(burst.parent_product_id) or from S3.
Subscriptions
subscription = client.subscriptions.create(
"Collection/Name eq 'SENTINEL-1'", events=["created"]
)
for notification in client.subscriptions.read(subscription.id, top=10):
print(notification.product_name)
client.subscriptions.acknowledge(subscription.id, notification.ack_id)
Traceability
trace = client.traceability.get_by_name("S2A_MSIL1C_20230420T100021_....SAFE.zip")
print(trace.hash, trace.hash_algorithm)
Command line interface
Install the cli extra, then:
cdse auth login # prompts for credentials and stores a session
cdse auth status
cdse odata search --collection SENTINEL-2 --cloud-cover-max 20 --limit 10
cdse odata download <product-id> -o product.zip
cdse stac search -c sentinel-2-l2a --bbox 4,50,5,51 --datetime 2024-05-01/2024-05-08
cdse stac download sentinel-2-l2a <item-id> --asset PRODUCT -o product.zip
cdse s3 download s3://eodata/Sentinel-2/.../PRODUCT.SAFE/ -o out/
cdse bursts search --swath IW1 --polarisation VH
cdse subscriptions list
cdse traceability get <product-name>
cdse auth logout
The session is stored under your user configuration directory with owner only
permissions. Add --json to the search commands for machine readable output.
Configuration
Every endpoint and limit can be overridden through a Settings object or
environment variables prefixed with CDSE_, for example CDSE_USERNAME,
CDSE_PASSWORD, CDSE_S3_ACCESS_KEY, CDSE_S3_SECRET_KEY,
CDSE_REQUESTS_PER_MINUTE, and CDSE_MAX_CONCURRENT_DOWNLOADS.
from cdse import Client, PasswordAuth, Settings
settings = Settings(requests_per_minute=120, max_concurrent_downloads=2)
client = Client(PasswordAuth("you@example.com", "pw"), settings=settings)
Notes and limitations
- Access tokens are valid for about ten minutes and refresh tokens for about sixty. After an hour of inactivity a new login is required unless credentials are available to authenticate again.
- The exact wire format of a few endpoints (OData product nodes and attributes, STAC asset authentication, and the subscription acknowledgement action) is not fully documented; these are parsed and called defensively and should be confirmed against the live service.
- Verifying the digital signature of a traceability record is delegated to the
official
trace-clitool. - openEO and Sentinel Hub are intentionally out of scope, as both already have dedicated Python clients.
Contributing
See CONTRIBUTING.md for the development setup, branching model, commit conventions, and release process.
License
See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cdse-0.1.1.tar.gz.
File metadata
- Download URL: cdse-0.1.1.tar.gz
- Upload date:
- Size: 1.9 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f9ab3c9829908e30faaedc0c541fc4af139e021a20e14f7dbbb1b707589f1ec5
|
|
| MD5 |
6606d3894aaf494041b151e36f7dab7f
|
|
| BLAKE2b-256 |
19d149b3f8ae92b737c3092d23286f08d6b1d6f5b76b6aa91572263692b132b1
|
Provenance
The following attestation bundles were made for cdse-0.1.1.tar.gz:
Publisher:
pypi-workflow.yml on polymood/cdse
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cdse-0.1.1.tar.gz -
Subject digest:
f9ab3c9829908e30faaedc0c541fc4af139e021a20e14f7dbbb1b707589f1ec5 - Sigstore transparency entry: 2008587530
- Sigstore integration time:
-
Permalink:
polymood/cdse@dce644a99fe0c276c7fcec617432d091425cc4db -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/polymood
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-workflow.yml@dce644a99fe0c276c7fcec617432d091425cc4db -
Trigger Event:
push
-
Statement type:
File details
Details for the file cdse-0.1.1-py3-none-any.whl.
File metadata
- Download URL: cdse-0.1.1-py3-none-any.whl
- Upload date:
- Size: 53.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5e72336573afbdab0b1c94b6ccceb7965b443f22b3725bea1d1e8f2293470e7b
|
|
| MD5 |
2c67663d2e695613c293ece978448432
|
|
| BLAKE2b-256 |
b07d5d18484dd906c22e0ac1c8c5608aeab40b1830aa26573e7ddf835c08cf49
|
Provenance
The following attestation bundles were made for cdse-0.1.1-py3-none-any.whl:
Publisher:
pypi-workflow.yml on polymood/cdse
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cdse-0.1.1-py3-none-any.whl -
Subject digest:
5e72336573afbdab0b1c94b6ccceb7965b443f22b3725bea1d1e8f2293470e7b - Sigstore transparency entry: 2008587706
- Sigstore integration time:
-
Permalink:
polymood/cdse@dce644a99fe0c276c7fcec617432d091425cc4db -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/polymood
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-workflow.yml@dce644a99fe0c276c7fcec617432d091425cc4db -
Trigger Event:
push
-
Statement type: