diff --git a/docs/index.md b/docs/index.md index f599fc0..bb396b0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -38,7 +38,7 @@ import zarr url = "https://uk1s3.embassy.ebi.ac.uk/idr/zarr/v0.4/idr0062A/6001240.zarr" # open the Zarr group -zgroup = zarr.open(url) +zgroup = zarr.open(url, mode='r') # group_model is a `GroupSpec`, i.e. a Pydantic model of a Zarr group group_model = Group.from_zarr(zgroup) @@ -113,7 +113,7 @@ print(multi_meta) arrays = [zgroup[d.path] for d in multi_meta[0].datasets] print(arrays) """ -[, , ] +[, , ] """ ``` diff --git a/src/pydantic_ome_ngff/utils.py b/src/pydantic_ome_ngff/utils.py index 16d7d19..399505c 100644 --- a/src/pydantic_ome_ngff/utils.py +++ b/src/pydantic_ome_ngff/utils.py @@ -2,6 +2,7 @@ from collections import Counter from typing import TYPE_CHECKING, Protocol, runtime_checkable +from zarr.storage import BaseStore import numpy as np @@ -38,3 +39,14 @@ def listify_numpy(data: Any) -> Any: if isinstance(data, np.ndarray): return data.tolist() return data + + +def get_path(store: BaseStore) -> str: + """ + Get a path from a zarr store + """ + if hasattr(store, "path"): + return store.path + + else: + return "" diff --git a/src/pydantic_ome_ngff/v04/multiscale.py b/src/pydantic_ome_ngff/v04/multiscale.py index 0afafd9..dc0ad82 100644 --- a/src/pydantic_ome_ngff/v04/multiscale.py +++ b/src/pydantic_ome_ngff/v04/multiscale.py @@ -25,6 +25,7 @@ ArrayLike, ChunkedArrayLike, duplicates, + get_path, ) from pydantic_ome_ngff.v04.axis import Axis, AxisType from pydantic_ome_ngff.v04.base import version @@ -296,16 +297,17 @@ def from_zarr(cls, node: zarr.Group) -> Group: A model of the Zarr group. """ # on unlistable storage backends, the members of this group will be {} - guess = GroupSpec.from_zarr(node) + guess = GroupSpec.from_zarr(node, depth=0) try: multi_meta_maybe = guess.attributes["multiscales"] except KeyError as e: + store_path = get_path(node.store) msg = ( "Failed to find mandatory `multiscales` key in the attributes of the Zarr group at " - f"{node.store}://{node.path}." + f"{node.store}://{store_path}://{node.path}." ) - raise ValueError(msg) from e + raise KeyError(msg) from e multi_meta = GroupAttrs(multiscales=multi_meta_maybe) members_tree_flat = {} @@ -331,7 +333,7 @@ def from_zarr(cls, node: zarr.Group) -> Group: members_normalized = GroupSpec.from_flat(members_tree_flat) guess_inferred_members = guess.model_copy( - update={"members": {**guess.members, **members_normalized.members}} + update={"members": members_normalized.members} ) return cls(**guess_inferred_members.model_dump()) @@ -347,7 +349,9 @@ def from_arrays( name: str | None = None, type: str | None = None, metadata: dict[str, Any] | None = None, - chunks: tuple[int, ...] | tuple[tuple[int, ...]] | Literal["auto"] = "auto", + chunks: tuple[int, ...] + | tuple[tuple[int, ...], ...] + | Literal["auto"] = "auto", compressor: Codec = DEFAULT_COMPRESSOR, fill_value: Any = 0, order: Literal["C", "F", "auto"] = "auto", diff --git a/tests/v04/test_multiscales.py b/tests/v04/test_multiscales.py index 90457af..c1d5202 100644 --- a/tests/v04/test_multiscales.py +++ b/tests/v04/test_multiscales.py @@ -377,7 +377,7 @@ def test_from_arrays( axes = all_axes[:ndim] else: axes = tuple([*all_axes[4:], *all_axes[:3]]) - + chunks_arg: tuple[tuple[int, ...], ...] | tuple[int, ...] | Literal["auto"] if chunks == "auto": chunks_arg = chunks chunks_expected = ( @@ -441,7 +441,12 @@ def test_from_zarr_missing_metadata( ) group_model = GroupSpec() group = group_model.to_zarr(store, path="test") - with pytest.raises(ValueError): + store_path = store.path if hasattr(store, "path") else "" + match = ( + "Failed to find mandatory `multiscales` key in the attributes of the Zarr group at " + f"{store}://{store_path}://{group.path}." + ) + with pytest.raises(KeyError, match=match): Group.from_zarr(group)