From 437f7f0208ad4ed5c191de5fb0699725131077c3 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sat, 13 Sep 2025 11:57:21 -0400 Subject: [PATCH 01/21] remove zarr from lib --- src/ome_zarr_models/__init__.py | 9 ++++++--- src/ome_zarr_models/_utils.py | 11 ++++++++--- src/ome_zarr_models/_v06/image.py | 21 ++++++++++++++++----- src/ome_zarr_models/_v06/image_label.py | 9 +++++++-- src/ome_zarr_models/_v06/labels.py | 16 ++++++++++++---- src/ome_zarr_models/common/validation.py | 13 +++++++++++-- src/ome_zarr_models/v04/_shared.py | 4 +++- src/ome_zarr_models/v04/base.py | 9 +++++++-- src/ome_zarr_models/v04/hcs.py | 8 ++++++-- src/ome_zarr_models/v04/image_label.py | 8 ++++++-- src/ome_zarr_models/v04/well.py | 12 ++++++++---- src/ome_zarr_models/v05/image.py | 20 +++++++++++++++----- src/ome_zarr_models/v05/image_label.py | 8 ++++++-- src/ome_zarr_models/v05/labels.py | 16 ++++++++++++---- 14 files changed, 123 insertions(+), 41 deletions(-) diff --git a/src/ome_zarr_models/__init__.py b/src/ome_zarr_models/__init__.py index 86451fcb..bb0979cf 100644 --- a/src/ome_zarr_models/__init__.py +++ b/src/ome_zarr_models/__init__.py @@ -1,7 +1,7 @@ -from importlib.metadata import PackageNotFoundError, version -from typing import Any +from __future__ import annotations -import zarr +from importlib.metadata import PackageNotFoundError, version +from typing import TYPE_CHECKING, Any import ome_zarr_models.v04.hcs import ome_zarr_models.v04.image @@ -17,6 +17,9 @@ from ome_zarr_models.v04.base import BaseGroupv04 from ome_zarr_models.v05.base import BaseGroupv05 +if TYPE_CHECKING: + import zarr + try: __version__ = version("ome_zarr_models") except PackageNotFoundError: # pragma: no cover diff --git a/src/ome_zarr_models/_utils.py b/src/ome_zarr_models/_utils.py index 0228811f..38658c9f 100644 --- a/src/ome_zarr_models/_utils.py +++ b/src/ome_zarr_models/_utils.py @@ -2,14 +2,19 @@ Private utilities. """ +from __future__ import annotations + from collections import Counter -from collections.abc import Hashable, Iterable from dataclasses import MISSING, fields, is_dataclass -from typing import TypeVar +from typing import TYPE_CHECKING, TypeVar import pydantic from pydantic import create_model -from zarr.abc.store import Store + +if TYPE_CHECKING: + from collections.abc import Hashable, Iterable + + from zarr.abc.store import Store T = TypeVar("T") diff --git a/src/ome_zarr_models/_v06/image.py b/src/ome_zarr_models/_v06/image.py index 0f657770..636a4017 100644 --- a/src/ome_zarr_models/_v06/image.py +++ b/src/ome_zarr_models/_v06/image.py @@ -1,10 +1,9 @@ -from collections.abc import Sequence -from typing import Any, Self +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, Self # Import needed for pydantic type resolution import pydantic_zarr # noqa: F401 -import zarr -import zarr.errors from pydantic import Field, JsonValue, model_validator from pydantic_zarr.v3 import AnyArraySpec, AnyGroupSpec, GroupSpec @@ -15,6 +14,12 @@ from ome_zarr_models.common.coordinate_transformations import _build_transforms from ome_zarr_models.common.validation import check_array_path +if TYPE_CHECKING: + from collections.abc import Sequence + + import zarr + + __all__ = ["Image", "ImageAttrs"] @@ -45,6 +50,12 @@ def from_zarr(cls, group: zarr.Group) -> Self: # type: ignore[override] group : zarr.Group A Zarr group that has valid OME-Zarr image metadata. """ + try: + import zarr + import zarr.errors + except ImportError as e: + raise ImportError("zarr is required to use this function") from e + # on unlistable storage backends, the members of this group will be {} group_spec: GroupSpec[dict[str, Any], Any] = GroupSpec.from_zarr(group, depth=0) @@ -87,7 +98,7 @@ def new( metadata: JsonValue | None = None, global_scale: Sequence[float] | None = None, global_translation: Sequence[float] | None = None, - ) -> "Image": + ) -> Image: """ Create a new `Image` from a sequence of multiscale arrays and spatial metadata. diff --git a/src/ome_zarr_models/_v06/image_label.py b/src/ome_zarr_models/_v06/image_label.py index d017157c..16b8ed8b 100644 --- a/src/ome_zarr_models/_v06/image_label.py +++ b/src/ome_zarr_models/_v06/image_label.py @@ -1,8 +1,9 @@ -from typing import Self +from __future__ import annotations + +from typing import TYPE_CHECKING, Self # Import needed for pydantic type resolution import pydantic_zarr # noqa: F401 -import zarr from pydantic import Field from ome_zarr_models._v06.base import BaseGroupv06, BaseOMEAttrs @@ -10,6 +11,10 @@ from ome_zarr_models._v06.image_label_types import Label from ome_zarr_models._v06.multiscales import Multiscale +if TYPE_CHECKING: + import zarr + + __all__ = ["ImageLabel", "ImageLabelAttrs"] diff --git a/src/ome_zarr_models/_v06/labels.py b/src/ome_zarr_models/_v06/labels.py index 6a5e581e..c1ebaa92 100644 --- a/src/ome_zarr_models/_v06/labels.py +++ b/src/ome_zarr_models/_v06/labels.py @@ -1,11 +1,11 @@ +from __future__ import annotations + from typing import TYPE_CHECKING, Any, Self import numpy as np # Import needed for pydantic type resolution import pydantic_zarr # noqa: F401 -import zarr -import zarr.errors from pydantic import Field, ValidationError, model_validator from pydantic_zarr.v3 import AnyArraySpec, AnyGroupSpec, GroupSpec @@ -13,6 +13,8 @@ from ome_zarr_models.common.validation import check_array_spec, check_group_spec if TYPE_CHECKING: + import zarr + from ome_zarr_models._v06.image_label import ImageLabel @@ -34,7 +36,7 @@ ] -def _check_valid_dtypes(labels: "Labels") -> "Labels": +def _check_valid_dtypes(labels: Labels) -> Labels: """ Check that all multiscales levels of a labels image are valid Label data types. """ @@ -102,6 +104,12 @@ def from_zarr(cls, group: zarr.Group) -> Self: # type: ignore[override] group : zarr.Group A Zarr group that has valid OME-Zarr label metadata. """ + try: + import zarr + import zarr.errors + except ImportError as e: + raise ImportError("zarr is required to use this function") from e + from ome_zarr_models._v06.image_label import ImageLabel attrs_dict = group.attrs.asdict() @@ -141,7 +149,7 @@ def label_paths(self) -> list[str]: """ return self.attributes.ome.labels - def get_image_labels_group(self, path: str) -> "ImageLabel": + def get_image_labels_group(self, path: str) -> ImageLabel: """ Get a image labels group at a given path. """ diff --git a/src/ome_zarr_models/common/validation.py b/src/ome_zarr_models/common/validation.py index cf1057aa..5d96b4f1 100644 --- a/src/ome_zarr_models/common/validation.py +++ b/src/ome_zarr_models/common/validation.py @@ -3,8 +3,6 @@ from typing import TYPE_CHECKING, Literal, TypeVar, overload -import zarr -import zarr.errors from pydantic import StringConstraints from pydantic_zarr.v2 import AnyArraySpec as AnyArraySpecv2 from pydantic_zarr.v2 import AnyGroupSpec as AnyGroupSpecv2 @@ -18,6 +16,8 @@ if TYPE_CHECKING: from collections.abc import Sequence + import zarr + __all__ = [ "AlphaNumericConstraint", @@ -87,6 +87,12 @@ def check_array_path( ValueError If the array doesn't exist, or the array is not the expected Zarr version. """ + try: + import zarr + import zarr.errors + except ImportError as e: + raise ImportError("zarr is required to use this function") from e + try: array = zarr.open_array(store=group.store_path, path=array_path, mode="r") except FileNotFoundError as e: @@ -151,6 +157,9 @@ def check_group_path( ValueError If the group doesn't exist, or the group is not the expected Zarr version. """ + import zarr + import zarr.errors + try: group = zarr.open_group(store=group.store_path, path=group_path, mode="r") except FileNotFoundError as e: diff --git a/src/ome_zarr_models/v04/_shared.py b/src/ome_zarr_models/v04/_shared.py index befd71f4..89570929 100644 --- a/src/ome_zarr_models/v04/_shared.py +++ b/src/ome_zarr_models/v04/_shared.py @@ -1,6 +1,7 @@ +from __future__ import annotations + from typing import TYPE_CHECKING, Any, TypeVar -import zarr from pydantic_zarr.v2 import AnyGroupSpec, GroupSpec from ome_zarr_models.base import BaseAttrs @@ -14,6 +15,7 @@ TAttrs = TypeVar("TAttrs", bound=BaseAttrs) if TYPE_CHECKING: + import zarr from pydantic_zarr.v2 import AnyArraySpec, AnyGroupSpec diff --git a/src/ome_zarr_models/v04/base.py b/src/ome_zarr_models/v04/base.py index 9ea2c8ef..af592b2f 100644 --- a/src/ome_zarr_models/v04/base.py +++ b/src/ome_zarr_models/v04/base.py @@ -1,10 +1,15 @@ -from typing import Generic, Literal, Self, TypeVar +from __future__ import annotations + +from typing import TYPE_CHECKING, Generic, Literal, Self, TypeVar -import zarr from pydantic_zarr.v2 import GroupSpec, TBaseItem from ome_zarr_models.base import BaseAttrs, BaseGroup +if TYPE_CHECKING: + import zarr + + T = TypeVar("T", bound=BaseAttrs) diff --git a/src/ome_zarr_models/v04/hcs.py b/src/ome_zarr_models/v04/hcs.py index 9ae89b80..671a8d7e 100644 --- a/src/ome_zarr_models/v04/hcs.py +++ b/src/ome_zarr_models/v04/hcs.py @@ -1,7 +1,8 @@ +from __future__ import annotations + from collections.abc import Generator, Mapping -from typing import Self +from typing import TYPE_CHECKING, Self -import zarr from pydantic import model_validator from pydantic_zarr.v2 import AnyGroupSpec, GroupSpec @@ -12,6 +13,9 @@ from ome_zarr_models.v04.plate import Plate from ome_zarr_models.v04.well import Well +if TYPE_CHECKING: + import zarr + __all__ = ["HCS", "HCSAttrs"] diff --git a/src/ome_zarr_models/v04/image_label.py b/src/ome_zarr_models/v04/image_label.py index 5faa1235..92f6fb1e 100644 --- a/src/ome_zarr_models/v04/image_label.py +++ b/src/ome_zarr_models/v04/image_label.py @@ -1,6 +1,7 @@ -from typing import Self +from __future__ import annotations + +from typing import TYPE_CHECKING, Self -import zarr from pydantic import Field from ome_zarr_models.base import BaseAttrs @@ -9,6 +10,9 @@ from ome_zarr_models.v04.image_label_types import Label from ome_zarr_models.v04.multiscales import Multiscale +if TYPE_CHECKING: + import zarr + __all__ = ["ImageLabel", "ImageLabelAttrs"] diff --git a/src/ome_zarr_models/v04/well.py b/src/ome_zarr_models/v04/well.py index aa8f753c..3e36999a 100644 --- a/src/ome_zarr_models/v04/well.py +++ b/src/ome_zarr_models/v04/well.py @@ -2,11 +2,9 @@ For reference, see the [well section of the OME-Zarr specification](https://ngff.openmicroscopy.org/0.4/#well-md). """ -from collections.abc import Generator -from typing import Self +from __future__ import annotations -import zarr -from pydantic_zarr.v2 import AnyGroupSpec +from typing import TYPE_CHECKING, Self from ome_zarr_models.base import BaseAttrs from ome_zarr_models.v04._shared import _from_zarr @@ -14,6 +12,12 @@ from ome_zarr_models.v04.image import Image from ome_zarr_models.v04.well_types import WellMeta +if TYPE_CHECKING: + from collections.abc import Generator + + import zarr + from pydantic_zarr.v2 import AnyGroupSpec + __all__ = ["Well", "WellAttrs"] diff --git a/src/ome_zarr_models/v05/image.py b/src/ome_zarr_models/v05/image.py index a82bdc30..00c706ae 100644 --- a/src/ome_zarr_models/v05/image.py +++ b/src/ome_zarr_models/v05/image.py @@ -1,10 +1,9 @@ -from collections.abc import Sequence -from typing import Any, Self +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, Self # Import needed for pydantic type resolution import pydantic_zarr # noqa: F401 -import zarr -import zarr.errors from pydantic import Field, JsonValue, model_validator from pydantic_zarr.v3 import AnyArraySpec, AnyGroupSpec, GroupSpec @@ -15,6 +14,11 @@ from ome_zarr_models.v05.labels import Labels from ome_zarr_models.v05.multiscales import Dataset, Multiscale +if TYPE_CHECKING: + from collections.abc import Sequence + + import zarr + __all__ = ["Image", "ImageAttrs"] @@ -45,6 +49,12 @@ def from_zarr(cls, group: zarr.Group) -> Self: # type: ignore[override] group : zarr.Group A Zarr group that has valid OME-Zarr image metadata. """ + try: + import zarr + import zarr.errors + except ImportError as e: + raise ImportError("zarr is required to use this function") from e + # on unlistable storage backends, the members of this group will be {} group_spec: GroupSpec[dict[str, Any], Any] = GroupSpec.from_zarr(group, depth=0) @@ -87,7 +97,7 @@ def new( metadata: JsonValue | None = None, global_scale: Sequence[float] | None = None, global_translation: Sequence[float] | None = None, - ) -> "Image": + ) -> Image: """ Create a new `Image` from a sequence of multiscale arrays and spatial metadata. diff --git a/src/ome_zarr_models/v05/image_label.py b/src/ome_zarr_models/v05/image_label.py index 01138ac2..9297d70f 100644 --- a/src/ome_zarr_models/v05/image_label.py +++ b/src/ome_zarr_models/v05/image_label.py @@ -1,8 +1,9 @@ -from typing import Self +from __future__ import annotations + +from typing import TYPE_CHECKING, Self # Import needed for pydantic type resolution import pydantic_zarr # noqa: F401 -import zarr from pydantic import Field from ome_zarr_models.v05.base import BaseGroupv05, BaseOMEAttrs @@ -10,6 +11,9 @@ from ome_zarr_models.v05.image_label_types import Label from ome_zarr_models.v05.multiscales import Multiscale +if TYPE_CHECKING: + import zarr + __all__ = ["ImageLabel", "ImageLabelAttrs"] diff --git a/src/ome_zarr_models/v05/labels.py b/src/ome_zarr_models/v05/labels.py index 8e4958cb..71fee613 100644 --- a/src/ome_zarr_models/v05/labels.py +++ b/src/ome_zarr_models/v05/labels.py @@ -1,11 +1,11 @@ +from __future__ import annotations + from typing import TYPE_CHECKING, Any, Self import numpy as np # Import needed for pydantic type resolution import pydantic_zarr # noqa: F401 -import zarr -import zarr.errors from pydantic import Field, ValidationError, model_validator from pydantic_zarr.v3 import AnyArraySpec, AnyGroupSpec, GroupSpec @@ -13,6 +13,8 @@ from ome_zarr_models.v05.base import BaseGroupv05, BaseOMEAttrs if TYPE_CHECKING: + import zarr + from ome_zarr_models.v05.image_label import ImageLabel @@ -34,7 +36,7 @@ ] -def _check_valid_dtypes(labels: "Labels") -> "Labels": +def _check_valid_dtypes(labels: Labels) -> Labels: """ Check that all multiscales levels of a labels image are valid Label data types. """ @@ -102,6 +104,12 @@ def from_zarr(cls, group: zarr.Group) -> Self: # type: ignore[override] group : zarr.Group A Zarr group that has valid OME-Zarr label metadata. """ + try: + import zarr + import zarr.errors + except ImportError as e: + raise ImportError("zarr is required to use this function") from e + from ome_zarr_models.v05.image_label import ImageLabel attrs_dict = group.attrs.asdict() @@ -141,7 +149,7 @@ def label_paths(self) -> list[str]: """ return self.attributes.ome.labels - def get_image_labels_group(self, path: str) -> "ImageLabel": + def get_image_labels_group(self, path: str) -> ImageLabel: """ Get a image labels group at a given path. """ From d47d7be8266751c45ea610134c3a39742bcfc9fe Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sat, 13 Sep 2025 11:57:34 -0400 Subject: [PATCH 02/21] add plate --- src/ome_zarr_models/_v06/__init__.py | 3 ++- src/ome_zarr_models/v04/__init__.py | 3 ++- src/ome_zarr_models/v05/__init__.py | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ome_zarr_models/_v06/__init__.py b/src/ome_zarr_models/_v06/__init__.py index 81d7ba3f..a059c402 100644 --- a/src/ome_zarr_models/_v06/__init__.py +++ b/src/ome_zarr_models/_v06/__init__.py @@ -2,6 +2,7 @@ from ome_zarr_models._v06.image import Image from ome_zarr_models._v06.image_label import ImageLabel from ome_zarr_models._v06.labels import Labels +from ome_zarr_models._v06.plate import Plate from ome_zarr_models._v06.well import Well -__all__ = ["HCS", "Image", "ImageLabel", "Labels", "Well"] +__all__ = ["HCS", "Image", "ImageLabel", "Labels", "Plate", "Well"] diff --git a/src/ome_zarr_models/v04/__init__.py b/src/ome_zarr_models/v04/__init__.py index 9ede45f6..c89df6a8 100644 --- a/src/ome_zarr_models/v04/__init__.py +++ b/src/ome_zarr_models/v04/__init__.py @@ -3,6 +3,7 @@ from ome_zarr_models.v04.image import Image from ome_zarr_models.v04.image_label import ImageLabel from ome_zarr_models.v04.labels import Labels +from ome_zarr_models.v04.plate import Plate from ome_zarr_models.v04.well import Well -__all__ = ["HCS", "BaseGroupv04", "Image", "ImageLabel", "Labels", "Well"] +__all__ = ["HCS", "BaseGroupv04", "Image", "ImageLabel", "Labels", "Plate", "Well"] diff --git a/src/ome_zarr_models/v05/__init__.py b/src/ome_zarr_models/v05/__init__.py index f27387be..a45f4051 100644 --- a/src/ome_zarr_models/v05/__init__.py +++ b/src/ome_zarr_models/v05/__init__.py @@ -2,6 +2,7 @@ from ome_zarr_models.v05.image import Image from ome_zarr_models.v05.image_label import ImageLabel from ome_zarr_models.v05.labels import Labels +from ome_zarr_models.v05.plate import Plate from ome_zarr_models.v05.well import Well -__all__ = ["HCS", "Image", "ImageLabel", "Labels", "Well"] +__all__ = ["HCS", "Image", "ImageLabel", "Labels", "Plate", "Well"] From ea80c34020cca2cc8de25b2208cf0ca8c05ff857 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sat, 13 Sep 2025 11:57:39 -0400 Subject: [PATCH 03/21] zarr optional in tests --- tests/_v06/test_general.py | 7 +++++- tests/_v06/test_hcs.py | 11 ++++++--- tests/_v06/test_image.py | 7 +++++- tests/_v06/test_image_label.py | 7 +++++- tests/_v06/test_labels.py | 7 +++++- tests/_v06/test_multiscales.py | 3 ++- tests/_v06/test_plate.py | 12 ++++++---- tests/_v06/test_well.py | 11 ++++++--- tests/conftest.py | 41 ++++++++++++++++++++-------------- tests/test_root.py | 3 ++- tests/v04/test_hcs.py | 3 ++- tests/v04/test_image.py | 7 +++++- tests/v04/test_image_label.py | 8 ++++++- tests/v04/test_labels.py | 7 +++++- tests/v04/test_well.py | 7 +++++- tests/v05/test_general.py | 7 +++++- tests/v05/test_hcs.py | 11 ++++++--- tests/v05/test_image.py | 7 +++++- tests/v05/test_image_label.py | 7 +++++- tests/v05/test_labels.py | 7 +++++- tests/v05/test_multiscales.py | 3 ++- tests/v05/test_plate.py | 12 ++++++---- tests/v05/test_well.py | 11 ++++++--- 23 files changed, 153 insertions(+), 53 deletions(-) diff --git a/tests/_v06/test_general.py b/tests/_v06/test_general.py index ec533da1..cf267a8b 100644 --- a/tests/_v06/test_general.py +++ b/tests/_v06/test_general.py @@ -2,15 +2,20 @@ General tests. """ +from __future__ import annotations + import re +from typing import TYPE_CHECKING import pytest from pydantic import ValidationError -from zarr.abc.store import Store from ome_zarr_models._v06.image import Image from tests._v06.conftest import json_to_zarr_group +if TYPE_CHECKING: + from zarr.abc.store import Store + def test_no_ome_version_fails(store: Store) -> None: zarr_group = json_to_zarr_group( diff --git a/tests/_v06/test_hcs.py b/tests/_v06/test_hcs.py index 62c2be2c..96d2722d 100644 --- a/tests/_v06/test_hcs.py +++ b/tests/_v06/test_hcs.py @@ -1,14 +1,19 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + import pytest -from zarr.abc.store import Store from ome_zarr_models._v06.hcs import HCS, HCSAttrs from ome_zarr_models._v06.plate import Acquisition, Column, Plate, Row, WellInPlate from tests._v06.conftest import json_to_zarr_group -from tests.conftest import UnlistableStore + +if TYPE_CHECKING: + from zarr.abc.store import Store def test_hcs(store: Store) -> None: - if isinstance(store, UnlistableStore): + if store.__class__.__name__ == "UnlistableStore": pytest.xfail("HCS does not work on unlistable stores") zarr_group = json_to_zarr_group(json_fname="hcs_example.json", store=store) ome_group = HCS.from_zarr(zarr_group) diff --git a/tests/_v06/test_image.py b/tests/_v06/test_image.py index 02e3954b..8c830eb3 100644 --- a/tests/_v06/test_image.py +++ b/tests/_v06/test_image.py @@ -1,8 +1,10 @@ +from __future__ import annotations + import re +from typing import TYPE_CHECKING import pytest from pydantic import ValidationError -from zarr.abc.store import Store from ome_zarr_models._v06.axes import Axis from ome_zarr_models._v06.coordinate_transformations import VectorScale @@ -11,6 +13,9 @@ from ome_zarr_models._v06.multiscales import Dataset, Multiscale from tests._v06.conftest import json_to_dict, json_to_zarr_group +if TYPE_CHECKING: + from zarr.abc.store import Store + def test_image(store: Store) -> None: zarr_group = json_to_zarr_group(json_fname="image_example.json", store=store) diff --git a/tests/_v06/test_image_label.py b/tests/_v06/test_image_label.py index b504ca98..d008bf55 100644 --- a/tests/_v06/test_image_label.py +++ b/tests/_v06/test_image_label.py @@ -1,4 +1,6 @@ -from zarr.abc.store import Store +from __future__ import annotations + +from typing import TYPE_CHECKING from ome_zarr_models._v06.axes import Axis from ome_zarr_models._v06.coordinate_transformations import VectorScale @@ -7,6 +9,9 @@ from ome_zarr_models._v06.multiscales import Dataset, Multiscale from tests._v06.conftest import json_to_zarr_group +if TYPE_CHECKING: + from zarr.abc.store import Store + def test_image_label(store: Store) -> None: zarr_group = json_to_zarr_group(json_fname="image_label_example.json", store=store) diff --git a/tests/_v06/test_labels.py b/tests/_v06/test_labels.py index f584f95b..fb8e44be 100644 --- a/tests/_v06/test_labels.py +++ b/tests/_v06/test_labels.py @@ -1,12 +1,17 @@ +from __future__ import annotations + import re +from typing import TYPE_CHECKING import numpy as np import pytest -from zarr.abc.store import Store from ome_zarr_models._v06.labels import Labels, LabelsAttrs from tests._v06.conftest import json_to_zarr_group +if TYPE_CHECKING: + from zarr.abc.store import Store + def test_labels(store: Store) -> None: zarr_group = json_to_zarr_group(json_fname="labels_example.json", store=store) diff --git a/tests/_v06/test_multiscales.py b/tests/_v06/test_multiscales.py index 5383c81c..1a76cf2f 100644 --- a/tests/_v06/test_multiscales.py +++ b/tests/_v06/test_multiscales.py @@ -5,7 +5,6 @@ import numpy as np import pytest -import zarr from pydantic import ValidationError from pydantic_zarr.v3 import AnyArraySpec, AnyGroupSpec, ArraySpec, GroupSpec @@ -403,6 +402,7 @@ def test_multiscale_group_missing_arrays() -> None: """ Test that creating a multiscale group fails when an expected Zarr array is missing """ + zarr = pytest.importorskip("zarr") arrays = ( zarr.zeros((10, 10)), zarr.zeros((5, 5)), @@ -437,6 +437,7 @@ def test_multiscale_group_ectopic_group() -> None: Test that creating a multiscale group fails when an expected Zarr array is actually a group """ + zarr = pytest.importorskip("zarr") arrays = ( zarr.zeros((10, 10)), zarr.zeros((5, 5)), diff --git a/tests/_v06/test_plate.py b/tests/_v06/test_plate.py index e7df1919..8c2636b9 100644 --- a/tests/_v06/test_plate.py +++ b/tests/_v06/test_plate.py @@ -1,17 +1,21 @@ +from __future__ import annotations + import re +from typing import TYPE_CHECKING import pytest from pydantic import ValidationError -from zarr.abc.store import Store from ome_zarr_models._v06.hcs import HCS from ome_zarr_models._v06.plate import Acquisition, Column, Plate, Row, WellInPlate from tests._v06.conftest import json_to_zarr_group -from tests.conftest import UnlistableStore + +if TYPE_CHECKING: + from zarr.abc.store import Store def test_example_plate_json(store: Store) -> None: - if isinstance(store, UnlistableStore): + if store.__class__.__name__ == "UnlistableStore": pytest.xfail("HCS does not work on unlistable stores") hcs: HCS = HCS.from_zarr( json_to_zarr_group(json_fname="plate_example_1.json", store=store) @@ -53,7 +57,7 @@ def test_example_plate_json(store: Store) -> None: def test_example_plate_json_2(store: Store) -> None: - if isinstance(store, UnlistableStore): + if store.__class__.__name__ == "UnlistableStore": pytest.xfail("HCS does not work on unlistable stores") hcs: HCS = HCS.from_zarr( json_to_zarr_group(json_fname="plate_example_2.json", store=store) diff --git a/tests/_v06/test_well.py b/tests/_v06/test_well.py index edd6ae99..969118f2 100644 --- a/tests/_v06/test_well.py +++ b/tests/_v06/test_well.py @@ -1,14 +1,19 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + import pytest -from zarr.abc.store import Store from ome_zarr_models._v06.well import Well, WellAttrs from ome_zarr_models._v06.well_types import WellImage, WellMeta from tests._v06.conftest import json_to_zarr_group -from tests.conftest import UnlistableStore + +if TYPE_CHECKING: + from zarr.abc.store import Store def test_well(store: Store) -> None: - if isinstance(store, UnlistableStore): + if store.__class__.__name__ == "UnlistableStore": pytest.xfail("Well does not work on unlistable stores") zarr_group = json_to_zarr_group(json_fname="well_example.json", store=store) ome_group = Well.from_zarr(zarr_group) diff --git a/tests/conftest.py b/tests/conftest.py index 6f5cafe1..a2f4b042 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,17 +2,15 @@ import json from pathlib import Path -from typing import TYPE_CHECKING, Any, Literal, Never, TypeVar +from typing import TYPE_CHECKING, Literal, TypeVar import pytest -import zarr -import zarr.storage -from zarr.abc.store import Store -from zarr.storage import LocalStore, MemoryStore from ome_zarr_models.base import BaseAttrs if TYPE_CHECKING: + from typing import Any, Never + from zarr.abc.store import Store @@ -73,27 +71,36 @@ def json_to_zarr_group( return group -class UnlistableStore(MemoryStore): - """ - A memory store that doesn't support listing. +try: + import zarr + import zarr.storage + from zarr.storage import LocalStore, MemoryStore +except ImportError: + pass +else: - Mimics other remote stores (e.g., HTTP) that don't support listing. - """ + class UnlistableStore(MemoryStore): + """ + A memory store that doesn't support listing. + + Mimics other remote stores (e.g., HTTP) that don't support listing. + """ - supports_listing: bool = False + supports_listing: bool = False - def list(self) -> Never: - raise NotImplementedError + def list(self) -> Never: + raise NotImplementedError - def list_dir(self, prefix: str) -> Never: - raise NotImplementedError + def list_dir(self, prefix: str) -> Never: + raise NotImplementedError - def list_prefix(self, prefix: str) -> Never: - raise NotImplementedError + def list_prefix(self, prefix: str) -> Never: + raise NotImplementedError @pytest.fixture(params=["MemoryStore", "LocalStore", "UnlistableStore"]) def store(request: pytest.FixtureRequest, tmp_path: Path) -> Store: + pytest.importorskip("zarr", reason="requires zarr") match request.param: case "MemoryStore": return MemoryStore() diff --git a/tests/test_root.py b/tests/test_root.py index 6993b8a0..6ffd8ec7 100644 --- a/tests/test_root.py +++ b/tests/test_root.py @@ -2,7 +2,6 @@ from pathlib import Path import pytest -import zarr from ome_zarr_models import open_ome_zarr from ome_zarr_models.v04.hcs import HCS @@ -10,6 +9,7 @@ def test_load_ome_zarr_group() -> None: + zarr = pytest.importorskip("zarr") hcs_group = zarr.open_group( get_examples_path(version="0.4") / "hcs_example.ome.zarr", mode="r" ) @@ -20,6 +20,7 @@ def test_load_ome_zarr_group() -> None: def test_load_ome_zarr_group_bad(tmp_path: Path) -> None: + zarr = pytest.importorskip("zarr") hcs_group = zarr.create_group(tmp_path / "test") with pytest.raises( RuntimeError, diff --git a/tests/v04/test_hcs.py b/tests/v04/test_hcs.py index 45349284..cc6a2692 100644 --- a/tests/v04/test_hcs.py +++ b/tests/v04/test_hcs.py @@ -1,4 +1,4 @@ -import zarr +import pytest from ome_zarr_models.common.omero import Channel, Omero, Window from ome_zarr_models.v04.axes import Axis @@ -12,6 +12,7 @@ def test_example_hcs() -> None: + zarr = pytest.importorskip("zarr") group = zarr.open_group( get_examples_path(version="0.4") / "hcs_example.ome.zarr", mode="r" ) diff --git a/tests/v04/test_image.py b/tests/v04/test_image.py index 812eb6e4..287c88ff 100644 --- a/tests/v04/test_image.py +++ b/tests/v04/test_image.py @@ -1,9 +1,11 @@ +from __future__ import annotations + import re +from typing import TYPE_CHECKING import numpy as np import pytest from pydantic_zarr.v2 import ArraySpec -from zarr.abc.store import Store from ome_zarr_models.common.coordinate_transformations import VectorTranslation from ome_zarr_models.v04.axes import Axis @@ -12,6 +14,9 @@ from ome_zarr_models.v04.multiscales import Dataset, Multiscale from tests.v04.conftest import json_to_zarr_group +if TYPE_CHECKING: + from zarr.abc.store import Store + def test_image(store: Store) -> None: zarr_group = json_to_zarr_group(json_fname="multiscales_example.json", store=store) diff --git a/tests/v04/test_image_label.py b/tests/v04/test_image_label.py index 9e2fc164..d04648c5 100644 --- a/tests/v04/test_image_label.py +++ b/tests/v04/test_image_label.py @@ -1,6 +1,9 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + import pytest from pydantic import ValidationError -from zarr.abc.store import Store from ome_zarr_models.v04.axes import Axis from ome_zarr_models.v04.coordinate_transformations import VectorScale @@ -14,6 +17,9 @@ from ome_zarr_models.v04.multiscales import Dataset, Multiscale from tests.v04.conftest import json_to_zarr_group +if TYPE_CHECKING: + from zarr.abc.store import Store + def test_image_label_example_json(store: Store) -> None: zarr_group = json_to_zarr_group(json_fname="image_label_example.json", store=store) diff --git a/tests/v04/test_labels.py b/tests/v04/test_labels.py index e28ec37c..c4d41191 100644 --- a/tests/v04/test_labels.py +++ b/tests/v04/test_labels.py @@ -1,9 +1,14 @@ -from zarr.abc.store import Store +from __future__ import annotations + +from typing import TYPE_CHECKING from ome_zarr_models.v04.image import Image from ome_zarr_models.v04.labels import LabelsAttrs from tests.v04.conftest import json_to_zarr_group +if TYPE_CHECKING: + from zarr.abc.store import Store + def test_image_with_labels(store: Store) -> None: zarr_group = json_to_zarr_group(json_fname="multiscales_example.json", store=store) diff --git a/tests/v04/test_well.py b/tests/v04/test_well.py index 2679e564..5788c371 100644 --- a/tests/v04/test_well.py +++ b/tests/v04/test_well.py @@ -1,9 +1,14 @@ -from zarr.abc.store import Store +from __future__ import annotations + +from typing import TYPE_CHECKING from ome_zarr_models.v04.well import Well, WellAttrs from ome_zarr_models.v04.well_types import WellImage, WellMeta from tests.v04.conftest import json_to_zarr_group +if TYPE_CHECKING: + from zarr.abc.store import Store + def test_well(store: Store) -> None: zarr_group = json_to_zarr_group(json_fname="well_example_1.json", store=store) diff --git a/tests/v05/test_general.py b/tests/v05/test_general.py index e60cf2d4..23c063a0 100644 --- a/tests/v05/test_general.py +++ b/tests/v05/test_general.py @@ -2,15 +2,20 @@ General tests. """ +from __future__ import annotations + import re +from typing import TYPE_CHECKING import pytest from pydantic import ValidationError -from zarr.abc.store import Store from ome_zarr_models.v05.image import Image from tests.v05.conftest import json_to_zarr_group +if TYPE_CHECKING: + from zarr.abc.store import Store + def test_no_ome_version_fails(store: Store) -> None: zarr_group = json_to_zarr_group( diff --git a/tests/v05/test_hcs.py b/tests/v05/test_hcs.py index 827bbfb1..ed45ec77 100644 --- a/tests/v05/test_hcs.py +++ b/tests/v05/test_hcs.py @@ -1,14 +1,19 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + import pytest -from zarr.abc.store import Store from ome_zarr_models.v05.hcs import HCS, HCSAttrs from ome_zarr_models.v05.plate import Acquisition, Column, Plate, Row, WellInPlate -from tests.conftest import UnlistableStore from tests.v05.conftest import json_to_zarr_group +if TYPE_CHECKING: + from zarr.abc.store import Store + def test_hcs(store: Store) -> None: - if isinstance(store, UnlistableStore): + if store.__class__.__name__ == "UnlistableStore": pytest.xfail("HCS does not work on unlistable stores") zarr_group = json_to_zarr_group(json_fname="hcs_example.json", store=store) ome_group = HCS.from_zarr(zarr_group) diff --git a/tests/v05/test_image.py b/tests/v05/test_image.py index 33b0f2a2..26b2949c 100644 --- a/tests/v05/test_image.py +++ b/tests/v05/test_image.py @@ -1,8 +1,10 @@ +from __future__ import annotations + import re +from typing import TYPE_CHECKING import pytest from pydantic import ValidationError -from zarr.abc.store import Store from ome_zarr_models.v05.axes import Axis from ome_zarr_models.v05.coordinate_transformations import VectorScale @@ -11,6 +13,9 @@ from ome_zarr_models.v05.multiscales import Dataset, Multiscale from tests.v05.conftest import json_to_dict, json_to_zarr_group +if TYPE_CHECKING: + from zarr.abc.store import Store + def test_image(store: Store) -> None: zarr_group = json_to_zarr_group(json_fname="image_example.json", store=store) diff --git a/tests/v05/test_image_label.py b/tests/v05/test_image_label.py index e38bad70..ec0b96a7 100644 --- a/tests/v05/test_image_label.py +++ b/tests/v05/test_image_label.py @@ -1,4 +1,6 @@ -from zarr.abc.store import Store +from __future__ import annotations + +from typing import TYPE_CHECKING from ome_zarr_models.v05.axes import Axis from ome_zarr_models.v05.coordinate_transformations import VectorScale @@ -7,6 +9,9 @@ from ome_zarr_models.v05.multiscales import Dataset, Multiscale from tests.v05.conftest import json_to_zarr_group +if TYPE_CHECKING: + from zarr.abc.store import Store + def test_image_label(store: Store) -> None: zarr_group = json_to_zarr_group(json_fname="image_label_example.json", store=store) diff --git a/tests/v05/test_labels.py b/tests/v05/test_labels.py index 0f0b605f..6e1ca0d3 100644 --- a/tests/v05/test_labels.py +++ b/tests/v05/test_labels.py @@ -1,12 +1,17 @@ +from __future__ import annotations + import re +from typing import TYPE_CHECKING import numpy as np import pytest -from zarr.abc.store import Store from ome_zarr_models.v05.labels import Labels, LabelsAttrs from tests.v05.conftest import json_to_zarr_group +if TYPE_CHECKING: + from zarr.abc.store import Store + def test_labels(store: Store) -> None: zarr_group = json_to_zarr_group(json_fname="labels_example.json", store=store) diff --git a/tests/v05/test_multiscales.py b/tests/v05/test_multiscales.py index 24593927..f33b6650 100644 --- a/tests/v05/test_multiscales.py +++ b/tests/v05/test_multiscales.py @@ -5,7 +5,6 @@ import numpy as np import pytest -import zarr from pydantic import ValidationError from pydantic_zarr.v3 import AnyArraySpec, AnyGroupSpec, ArraySpec, GroupSpec @@ -403,6 +402,7 @@ def test_multiscale_group_missing_arrays() -> None: """ Test that creating a multiscale group fails when an expected Zarr array is missing """ + zarr = pytest.importorskip("zarr") arrays = ( zarr.zeros((10, 10)), zarr.zeros((5, 5)), @@ -437,6 +437,7 @@ def test_multiscale_group_ectopic_group() -> None: Test that creating a multiscale group fails when an expected Zarr array is actually a group """ + zarr = pytest.importorskip("zarr") arrays = ( zarr.zeros((10, 10)), zarr.zeros((5, 5)), diff --git a/tests/v05/test_plate.py b/tests/v05/test_plate.py index 5b0506ec..ff0da95a 100644 --- a/tests/v05/test_plate.py +++ b/tests/v05/test_plate.py @@ -1,17 +1,21 @@ +from __future__ import annotations + import re +from typing import TYPE_CHECKING import pytest from pydantic import ValidationError -from zarr.abc.store import Store from ome_zarr_models.v05.hcs import HCS from ome_zarr_models.v05.plate import Acquisition, Column, Plate, Row, WellInPlate -from tests.conftest import UnlistableStore from tests.v05.conftest import json_to_zarr_group +if TYPE_CHECKING: + from zarr.abc.store import Store + def test_example_plate_json(store: Store) -> None: - if isinstance(store, UnlistableStore): + if store.__class__.__name__ == "UnlistableStore": pytest.xfail("HCS does not work on unlistable stores") hcs: HCS = HCS.from_zarr( json_to_zarr_group(json_fname="plate_example_1.json", store=store) @@ -53,7 +57,7 @@ def test_example_plate_json(store: Store) -> None: def test_example_plate_json_2(store: Store) -> None: - if isinstance(store, UnlistableStore): + if store.__class__.__name__ == "UnlistableStore": pytest.xfail("HCS does not work on unlistable stores") hcs: HCS = HCS.from_zarr( json_to_zarr_group(json_fname="plate_example_2.json", store=store) diff --git a/tests/v05/test_well.py b/tests/v05/test_well.py index 1005c948..f8f6bfa6 100644 --- a/tests/v05/test_well.py +++ b/tests/v05/test_well.py @@ -1,14 +1,19 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + import pytest -from zarr.abc.store import Store from ome_zarr_models.v05.well import Well, WellAttrs from ome_zarr_models.v05.well_types import WellImage, WellMeta -from tests.conftest import UnlistableStore from tests.v05.conftest import json_to_zarr_group +if TYPE_CHECKING: + from zarr.abc.store import Store + def test_well(store: Store) -> None: - if isinstance(store, UnlistableStore): + if store.__class__.__name__ == "UnlistableStore": pytest.xfail("Well does not work on unlistable stores") zarr_group = json_to_zarr_group(json_fname="well_example.json", store=store) ome_group = Well.from_zarr(zarr_group) From 617420d0d759d227af32b7931cc8b20dd272ba83 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sat, 13 Sep 2025 12:24:08 -0400 Subject: [PATCH 04/21] test on ci --- .github/workflows/python-package.yml | 20 +++++++------ pyproject.toml | 42 +++++++++++++++++----------- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 1a5aa409..3dc04a43 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -14,25 +14,29 @@ on: jobs: test: runs-on: ubuntu-latest + env: + UV_NO_SYNC: "1" strategy: matrix: - python-version: - - "3.11" + python-version: ["3.11"] + with-zarr: [true, false] + resolution: [highest, lowest-direct] steps: - uses: actions/checkout@v4 - name: Install uv - uses: astral-sh/setup-uv@v5 - - - name: Set up Python ${{ matrix.python-version }} - run: uv python install ${{ matrix.python-version }} + uses: astral-sh/setup-uv@v6 + with: + version: "2.6.0" + python-version: ${{ matrix.python-version }} - name: Install dependencies - run: uv sync --all-extras --dev + run: uv sync --no-dev --group test ${{ matrix.with-zarr && '--extra zarr' || '' }} + env: + UV_RESOLUTION: ${{ matrix.resolution }} - name: Run tests - # For example, using `pytest` run: uv run pytest - name: Upload coverage reports to Codecov diff --git a/pyproject.toml b/pyproject.toml index fcb0de1e..4a6a9be1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ dynamic = ["version"] description = "A minimal Python package for reading OME-Zarr (meta)data " readme = "README.md" requires-python = ">=3.11" -dependencies = ["zarr>= 3.1.1", "pydantic >= 2.11.5", "pydantic-zarr >= 0.8.2"] +dependencies = ["pydantic >= 2.11.5", "pydantic-zarr>=0.8.2"] maintainers = [{ name = "David Stansby" }] license = { file = "LICENSE" } classifiers = [ @@ -21,16 +21,8 @@ Repository = "https://github.com/ome-zarr-models/ome-zarr-models-py" # Changelog = "" [project.optional-dependencies] -docs = [ - "mkdocs>=1.6.1", - "mkdocstrings-python>=1.12.2", - "mkdocs-material", - "mkdocs-jupyter", - "matplotlib", - "rich", - "griffe-pydantic", - "fsspec[http]", -] +zarr = ["zarr>= 3.1.1"] + [tool.hatch.version] source = "vcs" @@ -40,12 +32,30 @@ requires = ["hatchling", "hatch-vcs"] build-backend = "hatchling.build" [dependency-groups] -docs = ["ome-zarr-models[docs]"] -dev = ["mypy", "ruff>=0.8", "pre-commit"] -test = ["pytest>=8.3.3", "pytest-cov"] +docs = [ + "mkdocs>=1.6.1", + "mkdocstrings-python>=1.12.2", + "mkdocs-material", + "mkdocs-jupyter >=0.25", + "matplotlib >=3.10", + "rich >= 14", + "griffe-pydantic", + "fsspec[http] >=2025", +] +dev = [ + { include-group = "docs" }, + { include-group = "test" }, + "mypy >=1.18", + "ruff>=0.8", + "pre-commit", + "ome-zarr-models[zarr]", +] +test = ["pytest>=8.3.3", "pytest-cov >=7.0.0"] + -[tool.uv] -default-groups = ["docs", "dev", "test"] +# TEMPORARY: remove before merge +[tool.uv.sources] +pydantic-zarr = { git = "https://github.com/tlambert03/pydantic-zarr", rev = "drop-zarr" } # Ruff configuration for linting and formatting # https://docs.astral.sh/ruff From 5cf700d645aea3dc60eca46e449b616121c8f719 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sat, 13 Sep 2025 12:27:16 -0400 Subject: [PATCH 05/21] readthedocs --- .readthedocs.yml | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index ff6c14c0..a44ff79a 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -3,15 +3,7 @@ version: 2 build: os: ubuntu-24.04 tools: - python: "3" - -python: - install: - - method: pip - path: . - extra_requirements: - - docs - - pydantic - -mkdocs: - configuration: mkdocs.yml + python: "3.13" + jobs: + install: + - pip install --group 'docs' From 5826c9cd5e568285b020043bd0dd8782aa90e058 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sat, 13 Sep 2025 12:28:01 -0400 Subject: [PATCH 06/21] back to uv --- .readthedocs.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index a44ff79a..54749449 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -3,7 +3,16 @@ version: 2 build: os: ubuntu-24.04 tools: - python: "3.13" + python: "3" jobs: + pre_create_environment: + - asdf plugin add uv + - asdf install uv latest + - asdf global uv latest + create_environment: + - uv venv "${READTHEDOCS_VIRTUALENV_PATH}" install: - - pip install --group 'docs' + - UV_PROJECT_ENVIRONMENT="${READTHEDOCS_VIRTUALENV_PATH}" uv sync --frozen --group docs + +mkdocs: + configuration: mkdocs.yml From 8df8318e127b749b420d98a9a5cbfeb61d24ac07 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sat, 13 Sep 2025 12:28:38 -0400 Subject: [PATCH 07/21] remove frozen --- .readthedocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 54749449..6e43d10f 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -12,7 +12,7 @@ build: create_environment: - uv venv "${READTHEDOCS_VIRTUALENV_PATH}" install: - - UV_PROJECT_ENVIRONMENT="${READTHEDOCS_VIRTUALENV_PATH}" uv sync --frozen --group docs + - UV_PROJECT_ENVIRONMENT="${READTHEDOCS_VIRTUALENV_PATH}" uv sync --group docs mkdocs: configuration: mkdocs.yml From 91ec25063f0328419abe1099fa994e4b18141c92 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sat, 13 Sep 2025 12:34:18 -0400 Subject: [PATCH 08/21] remove version --- .github/workflows/python-package.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 3dc04a43..d3098ba7 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -28,7 +28,6 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@v6 with: - version: "2.6.0" python-version: ${{ matrix.python-version }} - name: Install dependencies From 2bbce1469bbd58d39724b02594f1c8a5f3efd06f Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sat, 13 Sep 2025 12:44:21 -0400 Subject: [PATCH 09/21] mention extra in docs and add plat --- docs/index.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/index.md b/docs/index.md index cf588b68..bbfcaa67 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,6 +11,7 @@ The core of this package is a set of classes for representing different OME-Zarr | [`Labels`][ome_zarr_models.v05.Labels] | [`Labels`][ome_zarr_models.v04.Labels] | | [`ImageLabel`][ome_zarr_models.v05.ImageLabel] | [`ImageLabel`][ome_zarr_models.v04.ImageLabel] | | [`Well`][ome_zarr_models.v05.Well] | [`Well`][ome_zarr_models.v04.Well] | +| [`Plate`][ome_zarr_models.v05.Plate] | [`Plate`][ome_zarr_models.v04.Plate] | Each class has @@ -22,6 +23,8 @@ Each class has ```sh pip install ome-zarr-models +# or ... with zarr io support +pip install ome-zarr-models[zarr] ``` or From ac9722034e69848a8b67e34dad767f89d30730f8 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Thu, 18 Sep 2025 13:40:19 +0200 Subject: [PATCH 10/21] zarr optional --- tests/test_cli.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index e9ea5934..b3a76df1 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -3,7 +3,6 @@ from typing import TYPE_CHECKING, cast import pytest -import zarr from zarr.storage import LocalStore from ome_zarr_models._cli import main @@ -15,6 +14,8 @@ from pathlib import Path from typing import Any + import zarr + def populate_fake_data( zarr_group: zarr.Group, @@ -83,7 +84,7 @@ def test_cli_validate( capsys: pytest.CaptureFixture[str], ) -> None: """Test the CLI commands.""" - + pytest.importorskip("zarr") zarr_group = json_to_zarr_group( version=version, json_fname=json_fname, store=LocalStore(root=tmp_path) ) @@ -102,6 +103,7 @@ def test_cli_invalid( capsys: pytest.CaptureFixture[str], ) -> None: """Test the CLI with no command.""" + zarr = pytest.importorskip("zarr") zarr.create_group(tmp_path) monkeypatch.setattr("sys.argv", ["ome-zarr-models", cmd, str(tmp_path)]) with pytest.raises(SystemExit) as excinfo: From 78e99c347b379cd6101ac684573beb446599ba5b Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Thu, 18 Sep 2025 13:43:44 +0200 Subject: [PATCH 11/21] remove import plate --- docs/index.md | 1 - src/ome_zarr_models/_v06/__init__.py | 3 +-- src/ome_zarr_models/v04/__init__.py | 3 +-- src/ome_zarr_models/v05/__init__.py | 3 +-- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/docs/index.md b/docs/index.md index bbfcaa67..c0e2fc25 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,7 +11,6 @@ The core of this package is a set of classes for representing different OME-Zarr | [`Labels`][ome_zarr_models.v05.Labels] | [`Labels`][ome_zarr_models.v04.Labels] | | [`ImageLabel`][ome_zarr_models.v05.ImageLabel] | [`ImageLabel`][ome_zarr_models.v04.ImageLabel] | | [`Well`][ome_zarr_models.v05.Well] | [`Well`][ome_zarr_models.v04.Well] | -| [`Plate`][ome_zarr_models.v05.Plate] | [`Plate`][ome_zarr_models.v04.Plate] | Each class has diff --git a/src/ome_zarr_models/_v06/__init__.py b/src/ome_zarr_models/_v06/__init__.py index a059c402..81d7ba3f 100644 --- a/src/ome_zarr_models/_v06/__init__.py +++ b/src/ome_zarr_models/_v06/__init__.py @@ -2,7 +2,6 @@ from ome_zarr_models._v06.image import Image from ome_zarr_models._v06.image_label import ImageLabel from ome_zarr_models._v06.labels import Labels -from ome_zarr_models._v06.plate import Plate from ome_zarr_models._v06.well import Well -__all__ = ["HCS", "Image", "ImageLabel", "Labels", "Plate", "Well"] +__all__ = ["HCS", "Image", "ImageLabel", "Labels", "Well"] diff --git a/src/ome_zarr_models/v04/__init__.py b/src/ome_zarr_models/v04/__init__.py index c89df6a8..9ede45f6 100644 --- a/src/ome_zarr_models/v04/__init__.py +++ b/src/ome_zarr_models/v04/__init__.py @@ -3,7 +3,6 @@ from ome_zarr_models.v04.image import Image from ome_zarr_models.v04.image_label import ImageLabel from ome_zarr_models.v04.labels import Labels -from ome_zarr_models.v04.plate import Plate from ome_zarr_models.v04.well import Well -__all__ = ["HCS", "BaseGroupv04", "Image", "ImageLabel", "Labels", "Plate", "Well"] +__all__ = ["HCS", "BaseGroupv04", "Image", "ImageLabel", "Labels", "Well"] diff --git a/src/ome_zarr_models/v05/__init__.py b/src/ome_zarr_models/v05/__init__.py index a45f4051..f27387be 100644 --- a/src/ome_zarr_models/v05/__init__.py +++ b/src/ome_zarr_models/v05/__init__.py @@ -2,7 +2,6 @@ from ome_zarr_models.v05.image import Image from ome_zarr_models.v05.image_label import ImageLabel from ome_zarr_models.v05.labels import Labels -from ome_zarr_models.v05.plate import Plate from ome_zarr_models.v05.well import Well -__all__ = ["HCS", "Image", "ImageLabel", "Labels", "Plate", "Well"] +__all__ = ["HCS", "Image", "ImageLabel", "Labels", "Well"] From f76f228c7283488f874fd3e9c27cd68844b13f86 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Fri, 19 Sep 2025 18:32:51 +0200 Subject: [PATCH 12/21] fix tests --- src/ome_zarr_models/_v06/hcs.py | 4 +++- src/ome_zarr_models/_v06/well.py | 12 ++++++++---- src/ome_zarr_models/v05/hcs.py | 4 +++- src/ome_zarr_models/v05/well.py | 11 ++++++++--- tests/_v06/test_hcs.py | 2 -- tests/_v06/test_well.py | 2 -- tests/test_cli.py | 5 ++--- tests/v05/test_hcs.py | 2 -- tests/v05/test_well.py | 2 -- 9 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/ome_zarr_models/_v06/hcs.py b/src/ome_zarr_models/_v06/hcs.py index 0d187fe5..a60f1a6a 100644 --- a/src/ome_zarr_models/_v06/hcs.py +++ b/src/ome_zarr_models/_v06/hcs.py @@ -1,9 +1,10 @@ +from __future__ import annotations + from collections.abc import Generator, Mapping from typing import TYPE_CHECKING, Self # Import needed for pydantic type resolution import pydantic_zarr # noqa: F401 -import zarr from pydantic import model_validator from pydantic_zarr.v3 import GroupSpec @@ -14,6 +15,7 @@ from ome_zarr_models.common.well import WellGroupNotFoundError if TYPE_CHECKING: + import zarr from pydantic_zarr.v3 import AnyGroupSpec __all__ = ["HCS", "HCSAttrs"] diff --git a/src/ome_zarr_models/_v06/well.py b/src/ome_zarr_models/_v06/well.py index 4de9b122..59960b04 100644 --- a/src/ome_zarr_models/_v06/well.py +++ b/src/ome_zarr_models/_v06/well.py @@ -1,12 +1,16 @@ -# Import needed for pydantic type resolution -from typing import Self +from __future__ import annotations -import zarr +# Import needed for pydantic type resolution +from typing import TYPE_CHECKING, Self from ome_zarr_models._utils import _from_zarr_v3 from ome_zarr_models._v06.base import BaseGroupv06, BaseOMEAttrs from ome_zarr_models._v06.image import Image -from ome_zarr_models._v06.well_types import WellMeta + +if TYPE_CHECKING: + import zarr + + from ome_zarr_models._v06.well_types import WellMeta __all__ = ["Well", "WellAttrs"] diff --git a/src/ome_zarr_models/v05/hcs.py b/src/ome_zarr_models/v05/hcs.py index cff4a85c..a1fd99b1 100644 --- a/src/ome_zarr_models/v05/hcs.py +++ b/src/ome_zarr_models/v05/hcs.py @@ -1,9 +1,10 @@ +from __future__ import annotations + from collections.abc import Generator, Mapping from typing import TYPE_CHECKING, Self # Import needed for pydantic type resolution import pydantic_zarr # noqa: F401 -import zarr from pydantic import model_validator from pydantic_zarr.v3 import GroupSpec @@ -14,6 +15,7 @@ from ome_zarr_models.v05.well import Well if TYPE_CHECKING: + import zarr from pydantic_zarr.v3 import AnyGroupSpec diff --git a/src/ome_zarr_models/v05/well.py b/src/ome_zarr_models/v05/well.py index af5d330c..6afc2300 100644 --- a/src/ome_zarr_models/v05/well.py +++ b/src/ome_zarr_models/v05/well.py @@ -1,13 +1,18 @@ +from __future__ import annotations + # Import needed for pydantic type resolution -from typing import Self +from typing import TYPE_CHECKING, Self import pydantic_zarr # noqa: F401 -import zarr from ome_zarr_models._utils import _from_zarr_v3 from ome_zarr_models.v05.base import BaseGroupv05, BaseOMEAttrs from ome_zarr_models.v05.image import Image -from ome_zarr_models.v05.well_types import WellMeta + +if TYPE_CHECKING: + import zarr + + from ome_zarr_models.v05.well_types import WellMeta __all__ = ["Well", "WellAttrs"] diff --git a/tests/_v06/test_hcs.py b/tests/_v06/test_hcs.py index 7dc471a2..1c891ce7 100644 --- a/tests/_v06/test_hcs.py +++ b/tests/_v06/test_hcs.py @@ -2,8 +2,6 @@ from typing import TYPE_CHECKING -from zarr.abc.store import Store - from ome_zarr_models._v06.hcs import HCS, HCSAttrs from ome_zarr_models._v06.plate import Acquisition, Column, Plate, Row, WellInPlate from tests._v06.conftest import json_to_zarr_group diff --git a/tests/_v06/test_well.py b/tests/_v06/test_well.py index 1af646cd..6a8b4fe2 100644 --- a/tests/_v06/test_well.py +++ b/tests/_v06/test_well.py @@ -2,8 +2,6 @@ from typing import TYPE_CHECKING -from zarr.abc.store import Store - from ome_zarr_models._v06.well import Well, WellAttrs from ome_zarr_models._v06.well_types import WellImage, WellMeta from tests._v06.conftest import json_to_zarr_group diff --git a/tests/test_cli.py b/tests/test_cli.py index b3a76df1..db6d7fdd 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -3,7 +3,6 @@ from typing import TYPE_CHECKING, cast import pytest -from zarr.storage import LocalStore from ome_zarr_models._cli import main @@ -84,9 +83,9 @@ def test_cli_validate( capsys: pytest.CaptureFixture[str], ) -> None: """Test the CLI commands.""" - pytest.importorskip("zarr") + zarr = pytest.importorskip("zarr") zarr_group = json_to_zarr_group( - version=version, json_fname=json_fname, store=LocalStore(root=tmp_path) + version=version, json_fname=json_fname, store=zarr.LocalStore(root=tmp_path) ) populate_fake_data(zarr_group) monkeypatch.setattr("sys.argv", ["ome-zarr-models", cmd, str(tmp_path)]) diff --git a/tests/v05/test_hcs.py b/tests/v05/test_hcs.py index bfd78eec..cacef256 100644 --- a/tests/v05/test_hcs.py +++ b/tests/v05/test_hcs.py @@ -2,8 +2,6 @@ from typing import TYPE_CHECKING -from zarr.abc.store import Store - from ome_zarr_models.v05.hcs import HCS, HCSAttrs from ome_zarr_models.v05.plate import Acquisition, Column, Plate, Row, WellInPlate from tests.v05.conftest import json_to_zarr_group diff --git a/tests/v05/test_well.py b/tests/v05/test_well.py index 099339ce..7743fc6b 100644 --- a/tests/v05/test_well.py +++ b/tests/v05/test_well.py @@ -2,8 +2,6 @@ from typing import TYPE_CHECKING -from zarr.abc.store import Store - from ome_zarr_models.v05.well import Well, WellAttrs from ome_zarr_models.v05.well_types import WellImage, WellMeta from tests.v05.conftest import json_to_zarr_group From c0a09b7a648139009cbe610826035d10b889f15d Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Fri, 19 Sep 2025 18:35:31 +0200 Subject: [PATCH 13/21] refactor: move WellMeta import to the top for consistency --- src/ome_zarr_models/_v06/well.py | 2 +- src/ome_zarr_models/v05/well.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ome_zarr_models/_v06/well.py b/src/ome_zarr_models/_v06/well.py index 59960b04..bbf89837 100644 --- a/src/ome_zarr_models/_v06/well.py +++ b/src/ome_zarr_models/_v06/well.py @@ -6,11 +6,11 @@ from ome_zarr_models._utils import _from_zarr_v3 from ome_zarr_models._v06.base import BaseGroupv06, BaseOMEAttrs from ome_zarr_models._v06.image import Image +from ome_zarr_models._v06.well_types import WellMeta # noqa: TC001 if TYPE_CHECKING: import zarr - from ome_zarr_models._v06.well_types import WellMeta __all__ = ["Well", "WellAttrs"] diff --git a/src/ome_zarr_models/v05/well.py b/src/ome_zarr_models/v05/well.py index 6afc2300..8ee973ca 100644 --- a/src/ome_zarr_models/v05/well.py +++ b/src/ome_zarr_models/v05/well.py @@ -8,11 +8,11 @@ from ome_zarr_models._utils import _from_zarr_v3 from ome_zarr_models.v05.base import BaseGroupv05, BaseOMEAttrs from ome_zarr_models.v05.image import Image +from ome_zarr_models.v05.well_types import WellMeta # noqa: TC001 if TYPE_CHECKING: import zarr - from ome_zarr_models.v05.well_types import WellMeta __all__ = ["Well", "WellAttrs"] From 87f74470c903d4d19cb4b9fd89a0d27fb1060b1b Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Fri, 19 Sep 2025 18:36:36 +0200 Subject: [PATCH 14/21] remove noqa --- src/ome_zarr_models/_v06/well.py | 2 +- src/ome_zarr_models/v05/well.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ome_zarr_models/_v06/well.py b/src/ome_zarr_models/_v06/well.py index bbf89837..c33e5a64 100644 --- a/src/ome_zarr_models/_v06/well.py +++ b/src/ome_zarr_models/_v06/well.py @@ -6,7 +6,7 @@ from ome_zarr_models._utils import _from_zarr_v3 from ome_zarr_models._v06.base import BaseGroupv06, BaseOMEAttrs from ome_zarr_models._v06.image import Image -from ome_zarr_models._v06.well_types import WellMeta # noqa: TC001 +from ome_zarr_models._v06.well_types import WellMeta if TYPE_CHECKING: import zarr diff --git a/src/ome_zarr_models/v05/well.py b/src/ome_zarr_models/v05/well.py index 8ee973ca..ac1e8a3c 100644 --- a/src/ome_zarr_models/v05/well.py +++ b/src/ome_zarr_models/v05/well.py @@ -8,7 +8,7 @@ from ome_zarr_models._utils import _from_zarr_v3 from ome_zarr_models.v05.base import BaseGroupv05, BaseOMEAttrs from ome_zarr_models.v05.image import Image -from ome_zarr_models.v05.well_types import WellMeta # noqa: TC001 +from ome_zarr_models.v05.well_types import WellMeta if TYPE_CHECKING: import zarr From 7990cb40c7def94323cefe4677e9ba14c6ffa167 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Fri, 19 Sep 2025 18:38:04 +0200 Subject: [PATCH 15/21] fix test --- tests/test_cli.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index db6d7fdd..54b5df90 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -83,9 +83,11 @@ def test_cli_validate( capsys: pytest.CaptureFixture[str], ) -> None: """Test the CLI commands.""" - zarr = pytest.importorskip("zarr") + zarr_storage = pytest.importorskip("zarr.storage") zarr_group = json_to_zarr_group( - version=version, json_fname=json_fname, store=zarr.LocalStore(root=tmp_path) + version=version, + json_fname=json_fname, + store=zarr_storage.LocalStore(root=tmp_path), ) populate_fake_data(zarr_group) monkeypatch.setattr("sys.argv", ["ome-zarr-models", cmd, str(tmp_path)]) From 2c03e2b10c510c02c41ff8cfb3ae103024515ebd Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Tue, 30 Sep 2025 11:30:37 -0400 Subject: [PATCH 16/21] fix link --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 35d7e06d..4d7f1b44 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,7 +58,7 @@ test = ["pytest>=8.3.3", "pytest-cov >=7.0.0", "pytest-recording"] # TEMPORARY: remove before merge [tool.uv.sources] -pydantic-zarr = { git = "https://github.com/tlambert03/pydantic-zarr", rev = "drop-zarr" } +pydantic-zarr = { git = "https://github.com/zarr-developers/pydantic-zarr", rev = "main" } # Ruff configuration for linting and formatting # https://docs.astral.sh/ruff From 84ebe336697fc44d9b5febad77c5d04455a02565 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Tue, 30 Sep 2025 11:36:58 -0400 Subject: [PATCH 17/21] fix all the stuff --- docs/tutorial.py | 2 ++ tests/_v06/test_multiscales.py | 2 +- tests/test_root.py | 1 + tests/v04/test_image.py | 16 ++++++++-------- tests/v04/test_multiscales.py | 8 +++++--- tests/v05/test_image.py | 1 - tests/v05/test_multiscales.py | 2 +- 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/docs/tutorial.py b/docs/tutorial.py index 24840fac..0419a1eb 100644 --- a/docs/tutorial.py +++ b/docs/tutorial.py @@ -89,6 +89,7 @@ fill_value=0, codecs=[NamedConfig(name="bytes")], dimension_names=["y", "x"], + attributes={}, ), ArraySpec( shape=(100, 100), @@ -103,6 +104,7 @@ fill_value=0, codecs=[NamedConfig(name="bytes")], dimension_names=["y", "x"], + attributes={}, ), ] diff --git a/tests/_v06/test_multiscales.py b/tests/_v06/test_multiscales.py index 1a76cf2f..08ba97ad 100644 --- a/tests/_v06/test_multiscales.py +++ b/tests/_v06/test_multiscales.py @@ -454,7 +454,7 @@ def test_multiscale_group_ectopic_group() -> None: ) # remove an array, then re-create the model group_model_broken = group_model.model_copy( - update={"members": {array_names[0]: GroupSpec()}} + update={"members": {array_names[0]: GroupSpec(attributes={})}} ) with pytest.raises( ValidationError, diff --git a/tests/test_root.py b/tests/test_root.py index 0ceaa430..f356034f 100644 --- a/tests/test_root.py +++ b/tests/test_root.py @@ -59,6 +59,7 @@ def test_load_ome_zarr_group_bad(tmp_path: Path) -> None: @pytest.mark.vcr def test_load_remote_data() -> None: + pytest.importorskip("zarr") grp = open_ome_zarr( "https://uk1s3.embassy.ebi.ac.uk/idr/zarr/v0.5/idr0066/ExpA_VIP_ASLM_on.zarr", version="0.5", diff --git a/tests/v04/test_image.py b/tests/v04/test_image.py index 287c88ff..544414c0 100644 --- a/tests/v04/test_image.py +++ b/tests/v04/test_image.py @@ -82,8 +82,8 @@ def test_image(store: Store) -> None: def test_new_image() -> None: new_image = Image.new( array_specs=[ - ArraySpec(shape=(5, 5), chunks=(2, 2), dtype=np.uint8), - ArraySpec(shape=(3, 3), chunks=(2, 2), dtype=np.uint8), + ArraySpec(shape=(5, 5), chunks=(2, 2), dtype=np.uint8, attributes={}), + ArraySpec(shape=(3, 3), chunks=(2, 2), dtype=np.uint8, attributes={}), ], paths=["scale0", "scale1"], axes=[ @@ -169,8 +169,8 @@ def test_new_image() -> None: def example_image() -> Image: return Image.new( array_specs=[ - ArraySpec(shape=(5, 5), chunks=(2, 2), dtype=np.uint8), - ArraySpec(shape=(3, 3), chunks=(2, 2), dtype=np.uint8), + ArraySpec(shape=(5, 5), chunks=(2, 2), dtype=np.uint8, attributes={}), + ArraySpec(shape=(3, 3), chunks=(2, 2), dtype=np.uint8, attributes={}), ], paths=["scale0", "scale1"], axes=[ @@ -217,8 +217,8 @@ def test_new_image_wrong_transforms() -> None: ): Image.new( array_specs=[ - ArraySpec(shape=(5, 5), chunks=(2, 2), dtype=np.uint8), - ArraySpec(shape=(3, 3), chunks=(2, 2), dtype=np.uint8), + ArraySpec(shape=(5, 5), chunks=(2, 2), dtype=np.uint8, attributes={}), + ArraySpec(shape=(3, 3), chunks=(2, 2), dtype=np.uint8, attributes={}), ], paths=["scale0", "scale1"], axes=[ @@ -243,8 +243,8 @@ def test_global_transform(example_image: Image) -> None: def test_no_global_transform() -> None: new_image = Image.new( array_specs=[ - ArraySpec(shape=(5, 5), chunks=(2, 2), dtype=np.uint8), - ArraySpec(shape=(3, 3), chunks=(2, 2), dtype=np.uint8), + ArraySpec(shape=(5, 5), chunks=(2, 2), dtype=np.uint8, attributes={}), + ArraySpec(shape=(3, 3), chunks=(2, 2), dtype=np.uint8, attributes={}), ], paths=["scale0", "scale1"], axes=[ diff --git a/tests/v04/test_multiscales.py b/tests/v04/test_multiscales.py index b10eeae4..17dd9d5f 100644 --- a/tests/v04/test_multiscales.py +++ b/tests/v04/test_multiscales.py @@ -384,6 +384,7 @@ def test_multiscale_group_datasets_exist( shape=(1, 1, 1, 1), dtype="uint8", chunks=(1, 1, 1, 1), + attributes={}, ) for d in default_multiscale.datasets } @@ -394,6 +395,7 @@ def test_multiscale_group_datasets_exist( shape=(1, 1, 1, 1), dtype="uint8", chunks=(1, 1, 1, 1), + attributes={}, ) for d in default_multiscale.datasets } @@ -422,7 +424,7 @@ def test_multiscale_group_datasets_ndim() -> None: with pytest.raises(ValueError, match=re.escape(match)): Image.new( array_specs=[ - ArraySpec(shape=(10,), chunks=(10,), dtype="uint8") + ArraySpec(shape=(10,), chunks=(10,), dtype="uint8", attributes={}) for _ in range(bad_ndim) ], paths=[str(i) for i in range(true_ndim)], @@ -475,7 +477,7 @@ def test_multiscale_group_ectopic_group() -> None: ) # remove an array, then re-create the model group_model_broken = group_model.model_copy( - update={"members": {array_names[0]: GroupSpec()}} + update={"members": {array_names[0]: GroupSpec(attributes={})}} ) with pytest.raises( ValidationError, @@ -488,7 +490,7 @@ def test_from_zarr_missing_metadata( store: Store, request: pytest.FixtureRequest, ) -> None: - group_model: AnyGroupSpec = GroupSpec() + group_model: AnyGroupSpec = GroupSpec(attributes={}) group = group_model.to_zarr(store, path="test") # store_path = store.path if hasattr(store, "path") else "" match = "multiscales\n Field required" diff --git a/tests/v05/test_image.py b/tests/v05/test_image.py index 96efd750..94a30f35 100644 --- a/tests/v05/test_image.py +++ b/tests/v05/test_image.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING import pytest -import zarr from pydantic import ValidationError from ome_zarr_models.v05.axes import Axis diff --git a/tests/v05/test_multiscales.py b/tests/v05/test_multiscales.py index f33b6650..0b8004cd 100644 --- a/tests/v05/test_multiscales.py +++ b/tests/v05/test_multiscales.py @@ -454,7 +454,7 @@ def test_multiscale_group_ectopic_group() -> None: ) # remove an array, then re-create the model group_model_broken = group_model.model_copy( - update={"members": {array_names[0]: GroupSpec()}} + update={"members": {array_names[0]: GroupSpec(attributes={})}} ) with pytest.raises( ValidationError, From 8c99f80ced06a0e95a564be21ecde8633a879774 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Tue, 30 Sep 2025 11:38:38 -0400 Subject: [PATCH 18/21] fix pre-commit --- src/ome_zarr_models/_utils.py | 2 +- tests/v04/test_hcs.py | 1 - tests/v05/test_image.py | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ome_zarr_models/_utils.py b/src/ome_zarr_models/_utils.py index 021b621d..5f99cb7c 100644 --- a/src/ome_zarr_models/_utils.py +++ b/src/ome_zarr_models/_utils.py @@ -14,7 +14,7 @@ from pydantic import create_model if TYPE_CHECKING: - from collections.abc import Hashable, Iterable + from collections.abc import Iterable from zarr.abc.store import Store diff --git a/tests/v04/test_hcs.py b/tests/v04/test_hcs.py index 4a3d90e9..78f51913 100644 --- a/tests/v04/test_hcs.py +++ b/tests/v04/test_hcs.py @@ -15,7 +15,6 @@ from tests.conftest import get_examples_path if TYPE_CHECKING: - import zarr from pydantic import JsonValue diff --git a/tests/v05/test_image.py b/tests/v05/test_image.py index 94a30f35..64a743c5 100644 --- a/tests/v05/test_image.py +++ b/tests/v05/test_image.py @@ -14,6 +14,7 @@ from tests.v05.conftest import json_to_dict, json_to_zarr_group if TYPE_CHECKING: + import zarr from zarr.abc.store import Store From 242f4559282c72aec3329681f2160e8650325e41 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Tue, 30 Sep 2025 11:41:18 -0400 Subject: [PATCH 19/21] add members --- tests/v05/test_hcs.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/v05/test_hcs.py b/tests/v05/test_hcs.py index 28c26b3c..6f2a1e53 100644 --- a/tests/v05/test_hcs.py +++ b/tests/v05/test_hcs.py @@ -65,6 +65,7 @@ def test_non_existent_wells() -> None: does not specify explicitly that the Zarr groups have to exist. """ HCS( + members={}, attributes={ "ome": { "plate": { From 741d27b41279cf28cc6c7f729a8c9a023dbdec65 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Tue, 30 Sep 2025 11:42:21 -0400 Subject: [PATCH 20/21] lint --- tests/v05/test_hcs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/v05/test_hcs.py b/tests/v05/test_hcs.py index 6f2a1e53..4a6c3858 100644 --- a/tests/v05/test_hcs.py +++ b/tests/v05/test_hcs.py @@ -78,7 +78,7 @@ def test_non_existent_wells() -> None: }, "version": "0.5", } - } + }, ) From ded67fe8f45a5025fe0fb9e9e7b0aa23dc817d85 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Tue, 30 Sep 2025 11:50:59 -0400 Subject: [PATCH 21/21] update test dependencies to include fsspec and typos --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 4d7f1b44..d831c827 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,7 +53,7 @@ dev = [ "pre-commit", "ome-zarr-models[zarr]", ] -test = ["pytest>=8.3.3", "pytest-cov >=7.0.0", "pytest-recording"] +test = ["pytest>=8.3.3", "pytest-cov >=7.0.0", "pytest-recording", "fsspec[http] >=2025", "typos>=0.6.0"] # TEMPORARY: remove before merge