Metadata-Version: 2.4
Name: python-oda
Version: 0.2.0
Summary: Python client for the Ocean Data Access REST API.
License: NOT OPEN SOURCE
Author: eOdyn
Author-email: support-it@eodyn.com
Requires-Python: >=3.11, <3.14
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Provides-Extra: pandas
Provides-Extra: polars
Provides-Extra: xarray
Requires-Dist: h5netcdf (>=1.0.0) ; extra == "xarray"
Requires-Dist: h5py (>=3.0.0) ; extra == "xarray"
Requires-Dist: pandas (>=1.5.0) ; extra == "pandas"
Requires-Dist: polars (>=1.0.0) ; extra == "polars"
Requires-Dist: pyarrow (>=10.0.0) ; extra == "pandas"
Requires-Dist: pyarrow (>=10.0.0) ; extra == "polars"
Requires-Dist: pydantic (>=2.0.0,<3.0.0)
Requires-Dist: pydantic-geojson (>=0.3.2,<1.0.0)
Requires-Dist: pydantic-settings (>=2.10.1,<3.0.0)
Requires-Dist: pyjwt (>=2.13.0,<3.0.0)
Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
Requires-Dist: python-keycloak (>=7.1.1,<8.0.0)
Requires-Dist: scipy (>=1.17.1) ; extra == "xarray"
Requires-Dist: tqdm (>=4.0.0,<5.0.0)
Requires-Dist: typing-extensions (>=4.7.1,<5.0.0)
Requires-Dist: urllib3 (>=2.1.0,<3.0.0)
Requires-Dist: xarray (>=2022.0.0) ; extra == "xarray"
Project-URL: Documentation, https://it.pages.eodyn.com/oda/
Project-URL: Repository, https://gitlab.eodyn.com/it/data-platform/oda/oda
Description-Content-Type: text/markdown

# python-oda

[![Python version](https://img.shields.io/badge/Python-v3.13-blue?logo=python)](https://www.python.org/)
[![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v1.json)](https://github.com/charliermarsh/ruff)
[![mypy](https://img.shields.io/badge/mypy-checked-blue)](https://mypy-lang.org/)

`python-oda` is a Python client for **Ocean Data Access (ODA)**, [eOdyn](https://www.eodyn.com/)'s REST API.  
It lets you search and download oceanographic data through a filterable, typed API.

## Features

- **High-level, typed API** — browse products, datasets, documents and reports through a single
  entry point (`Oda`), with results returned as typed Pydantic models
- **Flexible authentication** — authenticate with a username/password, an existing JWT
  (access + refresh token), or OAuth2 client credentials
- **Automatic token handling** — access tokens are refreshed transparently, and API calls are
  retried once with a fresh token if they fail due to an expired/invalid token
- **Lazy, filterable pagination** — search products, datasets, documents and reports with
  server-side filtering and ordering, iterating results lazily as pages are fetched
- **Streaming downloads** — download documents and reports as a byte stream, with an optional
  progress bar (powered by `tqdm`) or a custom progress tracker
- **Built-in data readers** — convert downloaded documents directly into
  [pandas](https://pandas.pydata.org/), [polars](https://pola.rs/) or
  [xarray](https://xarray.dev/) objects, or plug in your own custom reader
- **Fully typed** with annotations and checked with mypy, [PEP561 compatible](https://www.python.org/dev/peps/pep-0561/)

## Installation

```bash
pip install python-oda
```

Optional extras are available for the built-in data readers: `python-oda[pandas]`,
`python-oda[polars]` and `python-oda[xarray]`.

## Usage

### Authentication

`oda` supports three authentication methods.  
Credentials can also be provided via the
`ODA_USERNAME`/`ODA_PASSWORD` environment variables, in which case `Oda()` can be instantiated
without an explicit `authentication` argument.

```python
from oda import Oda
from oda.core.authentication import AuthClient, AuthJWT, AuthUser

# Username / password
oda = Oda(authentication=AuthUser(username="my-user", password="my-password"))

# Existing JWT (access token, optionally with a refresh token)
oda = Oda(authentication=AuthJWT(access_token="...", refresh_token="..."))

# OAuth2 client credentials
oda = Oda(authentication=AuthClient(client_id="my-client", client_secret="my-secret"))
```

### Browsing products and datasets

```python
# Find products matching a filter
for product in oda.products.find(provider="eOdyn", order_by="+name"):
    print(product)

# Find datasets matching a filter
for dataset in oda.datasets.find(type="currents", tags_in=["OS"]):
    print(dataset)
```

### Finding and downloading documents

```python
# List documents in a dataset
for document in oda.documents.find(dataset_name="altimetry-sealevel-l3-swot"):
    print(document.name, document.start_datetime, document.size)

# Download all matching documents to disk, with a progress bar
oda.documents.download(dataset_name="altimetry-sealevel-l3-swot", output_path="./downloads")

# Or download a single document into memory and load it directly as a DataFrame
document = next(iter(oda.documents.find(dataset_name="altimetry-sealevel-l3-swot", name="SWOT_L3_LR_SSH_Expert_outre-mer_053_464_20260726T173752_20260726T182918_v3.0.nc")))
df = document.download().to_pandas()  # also available: .to_polars(), .to_xarray()

# Filter documents by date range
from datetime import datetime

for document in oda.documents.find(
    dataset_name="altimetry-sealevel-l3-swot",
    date__gte=datetime(2026, 7, 1),
    date__lte=datetime(2026, 7, 26),
):
    print(document.name, document.start_datetime)
```

### Finding and downloading reports

```python
for report in oda.reports.find(dataset_name="altimetry-sealevel-l3-swot", document_name="SWOT_L3_LR_SSH_Expert_outre-mer_053_464_20260726T173752_20260726T182918_v3.0.nc"):
    print(report)

oda.reports.download(
    dataset_name="altimetry-sealevel-l3-swot",
    document_name="SWOT_L3_LR_SSH_Expert_outre-mer_053_464_20260726T173752_20260726T182918_v3.0.nc",
    output_path="./downloads",
)
```

## Contact

For questions or support, contact [support-it@eodyn.com](mailto:support-it@eodyn.com).

