---
name: eocube-data-access
description: "Open STAC assets from EOCube object storage inside notebooks: presign s3:// hrefs with sign_in_place, read COGs with rioxarray or odc-stac, use the right filesystem object for the primary and personal buckets, download files with the eocube CLI, and avoid the presigning and Dask-worker pitfalls."
license: Apache-2.0
compatibility: "EOCube.RO JupyterHub notebooks (notebooks.eocube.ro) with the `eocube` package installed; off-hub use needs `eocube auth login` and AWS_DEFAULT_REGION=ro-west-uvt-01."
---

## Set up the kernel once

```python
from eocube.integrations.notebooks import setup_notebook, sign_in_place, fs, user_fs
setup_notebook()   # applies nest_asyncio so the eocube helpers work inside Jupyter
```

`fs` is an s3fs filesystem on the primary storage (`storage.svc.uvt-01.eocube.ro`),
`user_fs` on the personal bucket (`s3.svc.uvt-01.eocube.ro`). Both renew their own
STS credentials; use them for listing and file transfers from the notebook kernel.

## From search results to readable hrefs

STAC asset hrefs are `s3://bucket/key`. Readers such as rioxarray need an HTTP URL:

1. **Private or restricted buckets: presign.** `sign_in_place` rewrites hrefs inside the
   dict you pass. Keep that dict; a throwaway `to_dict()` changes nothing you hold.

```python
import pystac
unsigned = items.to_dict()                # keep the unsigned copy, re-sign from it later
signed = pystac.ItemCollection.from_dict(unsigned).to_dict()
sign_in_place(signed)
signed_items = pystac.ItemCollection.from_dict(signed)
```

2. **Public buckets: rewrite instead.** `s3://bucket/key` becomes
   `https://storage.svc.uvt-01.eocube.ro/bucket/key` (path-style addressing).

Presigned URLs are valid up to 7 days but stop working when the credentials that signed
them expire with the session. Never cache signed URLs across sessions; re-sign from the
unsigned originals.

## Reading rasters

```python
import rioxarray
da = rioxarray.open_rasterio(href, overview_level=2, chunks={"x": 1024, "y": 1024})
```

- `overview_level` reads a COG overview: fast previews without touching full resolution.
- For multi-item cubes use `odc.stac.load(signed_items, bands=[...], chunks={...},
  crs=..., resolution=...)` or `stackstac.stack(signed_items, ...)`; both take the signed
  item collection.
- Clip to an AOI with `da.rio.clip(gdf.geometry, gdf.crs)` after reprojecting the AOI.

## Downloading files instead of streaming

- CLI, bulk: `eocube services stac search --collections <id> --json > dataset.json`
  then `eocube services stac download dataset.json --destination ./data`
  (`--roles data`, `--assets <name>`, `--workers N`, `--dry-run`).
- Python, single objects: `fs.get("bucket/key", "local.tif")` or
  `user_fs.get(...)` for the personal bucket.
- MCP: `storage_ls` lists; there is no download tool on the sidecar.

## Off the hub

Set `AWS_DEFAULT_REGION=ro-west-uvt-01` and log in with `eocube auth login`; without the
region, signing fails with HTTP 403. Path-style addressing (`AWS_VIRTUAL_HOSTING=FALSE`)
is required for every S3 client.

## Dask

Workers receive **hrefs** (presigned URLs or public HTTPS URLs), never the `fs` /
`user_fs` objects or sessions. Build the signed item collection in the notebook, then
hand it to `odc.stac.load`/`stackstac` with chunks so workers fetch windows themselves.
See `eocube-dask`.

## Pitfalls

- `sign_in_place` on a dict you then discard: nothing is signed.
- Mixed buckets in one item collection are fine: signing routes each href to the
  filesystem that owns its bucket.
- Expired STS credentials inside a long kernel: re-import `fs`/`user_fs` or restart the
  kernel; the hub injects fresh credentials at server start.
- Reading full resolution of a whole tile for a plot: use `overview_level` or a clip.
