Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,28 @@ 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:
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
Expand Down
17 changes: 9 additions & 8 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ build:
os: ubuntu-24.04
tools:
python: "3"

python:
install:
- method: pip
path: .
extra_requirements:
- docs
- pydantic
jobs:
pre_create_environment:
- asdf plugin add uv
- asdf install uv latest
- asdf global uv latest
create_environment:
- uv venv "${READTHEDOCS_VIRTUALENV_PATH}"
install:
- UV_PROJECT_ENVIRONMENT="${READTHEDOCS_VIRTUALENV_PATH}" uv sync --group docs

mkdocs:
configuration: mkdocs.yml
3 changes: 3 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down
42 changes: 26 additions & 16 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand All @@ -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"
Expand All @@ -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
Expand Down
9 changes: 6 additions & 3 deletions src/ome_zarr_models/__init__.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down
11 changes: 8 additions & 3 deletions src/ome_zarr_models/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down
3 changes: 2 additions & 1 deletion src/ome_zarr_models/_v06/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
21 changes: 16 additions & 5 deletions src/ome_zarr_models/_v06/image.py
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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"]


Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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.
Expand Down
9 changes: 7 additions & 2 deletions src/ome_zarr_models/_v06/image_label.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
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
from ome_zarr_models._v06.image import Image
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"]


Expand Down
16 changes: 12 additions & 4 deletions src/ome_zarr_models/_v06/labels.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
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

from ome_zarr_models._v06.base import BaseGroupv06, BaseOMEAttrs
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


Expand All @@ -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.
"""
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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.
"""
Expand Down
13 changes: 11 additions & 2 deletions src/ome_zarr_models/common/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -18,6 +16,8 @@
if TYPE_CHECKING:
from collections.abc import Sequence

import zarr


__all__ = [
"AlphaNumericConstraint",
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
3 changes: 2 additions & 1 deletion src/ome_zarr_models/v04/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
4 changes: 3 additions & 1 deletion src/ome_zarr_models/v04/_shared.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -14,6 +15,7 @@
TAttrs = TypeVar("TAttrs", bound=BaseAttrs)

if TYPE_CHECKING:
import zarr
from pydantic_zarr.v2 import AnyArraySpec, AnyGroupSpec


Expand Down
Loading