diff --git a/CHANGES.md b/CHANGES.md index 8da2cacec..99513cdf2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -64,10 +64,22 @@ To enforce the old behaviour, provide the `var_configs` keyword-argument and set `recover_nan` to `True` for desired variables. +### Fixes + +* When using the `xcube.webapi.viewer.Viewer` class in Jupyter notebooks + multi-level datasets opened from S3 or from deeper subdirectories into + the local filesystem are now fully supported. (#1007) + * The class `MaskSet()` of module `xcube.core.maskset` now correctly recognises the variable attributes `flag_values`, `flag_masks`, `flag_meanings` when their values are lists (ESA CCI LC data encodes them as JSON arrays). (#1002) +* Fixed an issue with xcube server `/timeseries` endpoint that returned + status 500 if a given dataset used a CRS other geographic and the + geometry was not a point. (#995) + +* Fixed broken table of contents links in dataset convention document. + ### Incompatible API changes @@ -101,14 +113,6 @@ - Removed endpoint `/datasets/{datasetId}/vars/{varName}/tiles2/{z}/{y}/{x}` from xcube server. -### Fixes - -* Fixed an issue with xcube server `/timeseries` endpoint that returned - status 500 if a given dataset used a CRS other geographic and the - geometry was not a point. (#995) - -* Fixed broken table of contents links in dataset convention document. - ### Other changes * Make tests compatible with PyTest 8.2.0. (#973) diff --git a/test/webapi/viewer/test_viewer.py b/test/webapi/viewer/test_viewer.py index 56c26ece6..9a8b24492 100644 --- a/test/webapi/viewer/test_viewer.py +++ b/test/webapi/viewer/test_viewer.py @@ -9,6 +9,7 @@ from typing import Optional, Any, Union import pytest +from xcube.core.mldataset import BaseMultiLevelDataset from xcube.core.new import new_cube from xcube.server.api import ApiError @@ -210,6 +211,21 @@ def test_add_and_remove_dataset(self): with pytest.raises(ApiError.NotFound): self.viewer.datasets_ctx.get_dataset_config(ds_id_2) + # Verifies https://github.com/xcube-dev/xcube/issues/1007 + def test_add_dataset_with_slash_path(self): + viewer = self.get_viewer(STYLES_CONFIG) + + ml_ds = BaseMultiLevelDataset( + new_cube(variables={"analysed_sst": 280.0}), + ds_id="mybucket/mysst.levels", + ) + ds_id = viewer.add_dataset(ml_ds, title="My SST") + + self.assertEqual("mybucket-mysst.levels", ds_id) + + ds_config = self.viewer.datasets_ctx.get_dataset_config(ds_id) + self.assertEqual({"Identifier": ds_id, "Title": "My SST"}, ds_config) + def test_add_dataset_with_style(self): viewer = self.get_viewer(STYLES_CONFIG) diff --git a/xcube/core/mldataset/fs.py b/xcube/core/mldataset/fs.py index 1816b6385..932b4ee92 100644 --- a/xcube/core/mldataset/fs.py +++ b/xcube/core/mldataset/fs.py @@ -50,6 +50,12 @@ def __init__( fs, path = fsspec.core.url_to_fs(path, **(fs_kwargs or {})) assert_instance(fs, fsspec.AbstractFileSystem, name="fs") assert_instance(path, str, name="data_id") + # TODO: Setting ds_id=path is likely the root cause for + # https://github.com/xcube-dev/xcube/issues/1007. + # Then, the actual fix is to replace slashes by dashes or underscores. + # But this requires deeper investigation and more test cases. + # A quick fix has been applied in `xcube.webapi.viewer.Viewer.add_dataset()` + # implementation. forman, 2024-06-07 super().__init__(ds_id=path) self._path = path self._fs = fs diff --git a/xcube/webapi/compute/context.py b/xcube/webapi/compute/context.py index c3b4218e9..e5ca8fea6 100644 --- a/xcube/webapi/compute/context.py +++ b/xcube/webapi/compute/context.py @@ -7,7 +7,7 @@ import inspect import concurrent.futures import datetime -from typing import Dict, Any, Optional, Callable +from typing import Any, Optional, Callable import traceback import xarray as xr diff --git a/xcube/webapi/datasets/context.py b/xcube/webapi/datasets/context.py index dd6c17273..7cdcee976 100644 --- a/xcube/webapi/datasets/context.py +++ b/xcube/webapi/datasets/context.py @@ -183,6 +183,13 @@ def add_dataset( ml_dataset = BaseMultiLevelDataset(dataset, ds_id=ds_id) else: ml_dataset = dataset + if not ds_id: + _ds_id = ml_dataset.ds_id + # TODO: Fixes https://github.com/xcube-dev/xcube/issues/1007, but + # this does not solve the likely root cause + # in xcube.core.mldataset.fs.FsMultiLevelDataset, see ctor. + if "/" in _ds_id: + ds_id = _ds_id.replace("/", "-") if ds_id: ml_dataset = IdentityMultiLevelDataset(dataset, ds_id=ds_id) dataset = ml_dataset.base_dataset diff --git a/xcube/webapi/viewer/viewer.py b/xcube/webapi/viewer/viewer.py index 2e45b5389..13aa49f65 100644 --- a/xcube/webapi/viewer/viewer.py +++ b/xcube/webapi/viewer/viewer.py @@ -7,7 +7,7 @@ import socket import threading from pathlib import Path -from typing import Optional, Union, Any, Tuple, Dict +from typing import Any, Optional, Union from collections.abc import Iterable from collections.abc import Mapping @@ -62,7 +62,7 @@ class Viewer: The `Viewer` class takes a xcube server configuration as first argument. More details regarding configuration parameters are given in the `server documentation `_. - The full configuration reference can be generated by excecuting CLI command + The full configuration reference can be generated by executing CLI command ``$ xcube serve --show configschema``. Args: