Skip to content

Commit

Permalink
Include axes validation in write_multiscales_metadata
Browse files Browse the repository at this point in the history
- Split the axes validation logic from the axes guessing logic so it can
be re-used
- Add tests covering the scenarios of format 0.1/0.2 as well as invalid axes
  • Loading branch information
sbesson committed Dec 16, 2021
1 parent 2d581d1 commit 0c71fbe
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 27 deletions.
60 changes: 33 additions & 27 deletions ome_zarr/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,34 +40,36 @@ def _validate_axes_names(
if isinstance(axes, str):
axes = list(axes)

if axes is not None:
if len(axes) != ndim:
raise ValueError("axes length must match number of dimensions")
# from https://github.com/constantinpape/ome-ngff-implementations/
val_axes = tuple(axes)
if ndim == 2:
if val_axes != ("y", "x"):
raise ValueError(f"2D data must have axes ('y', 'x') {val_axes}")
elif ndim == 3:
if val_axes not in [("z", "y", "x"), ("c", "y", "x"), ("t", "y", "x")]:
raise ValueError(
"3D data must have axes ('z', 'y', 'x') or ('c', 'y', 'x')"
" or ('t', 'y', 'x'), not %s" % (val_axes,)
)
elif ndim == 4:
if val_axes not in [
("t", "z", "y", "x"),
("c", "z", "y", "x"),
("t", "c", "y", "x"),
]:
raise ValueError("4D data must have axes tzyx or czyx or tcyx")
else:
if val_axes != ("t", "c", "z", "y", "x"):
raise ValueError("5D data must have axes ('t', 'c', 'z', 'y', 'x')")

if len(axes) != ndim:
raise ValueError("axes length must match number of dimensions")
_validate_axes(axes)
return axes


def _validate_axes(axes: List[str], fmt: Format = CurrentFormat()) -> None:

val_axes = tuple(axes)
if len(val_axes) == 2:
if val_axes != ("y", "x"):
raise ValueError(f"2D data must have axes ('y', 'x') {val_axes}")
elif len(val_axes) == 3:
if val_axes not in [("z", "y", "x"), ("c", "y", "x"), ("t", "y", "x")]:
raise ValueError(
"3D data must have axes ('z', 'y', 'x') or ('c', 'y', 'x')"
" or ('t', 'y', 'x'), not %s" % (val_axes,)
)
elif len(val_axes) == 4:
if val_axes not in [
("t", "z", "y", "x"),
("c", "z", "y", "x"),
("t", "c", "y", "x"),
]:
raise ValueError("4D data must have axes tzyx or czyx or tcyx")
else:
if val_axes != ("t", "c", "z", "y", "x"):
raise ValueError("5D data must have axes ('t', 'c', 'z', 'y', 'x')")


def write_multiscale(
pyramid: List,
group: zarr.Group,
Expand Down Expand Up @@ -111,7 +113,7 @@ def write_multiscales_metadata(
group: zarr.Group,
paths: List[str],
fmt: Format = CurrentFormat(),
axes: Union[str, List[str]] = None,
axes: List[str] = None,
) -> None:
"""
Write the multiscales metadata in the group metadata
Expand All @@ -137,7 +139,11 @@ def write_multiscales_metadata(
}
]
if axes is not None:
multiscales[0]["axes"] = axes
if fmt.version in ("0.1", "0.2"):
LOGGER.info("axes ignored for version 0.1 or 0.2")
else:
_validate_axes(axes, fmt)
multiscales[0]["axes"] = axes
group.attrs["multiscales"] = multiscales


Expand Down
22 changes: 22 additions & 0 deletions tests/test_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,25 @@ def test_axes(self, axes):
write_multiscales_metadata(self.root, ["0"], axes=axes)
assert "multiscales" in self.root.attrs
assert self.root.attrs["multiscales"][0]["axes"] == axes

@pytest.mark.parametrize("fmt", (FormatV01(), FormatV02()))
def test_axes_ignored(self, fmt):
write_multiscales_metadata(
self.root, ["0"], fmt=fmt, axes=["t", "c", "z", "y", "x"]
)
assert "multiscales" in self.root.attrs
assert "axes" not in self.root.attrs["multiscales"][0]

@pytest.mark.parametrize(
"axes",
(
[],
["i", "j"],
["x", "y"],
["y", "x", "c"],
["x", "y", "z", "c", "t"],
),
)
def test_invalid_0_3_axes(self, axes):
with pytest.raises(ValueError):
write_multiscales_metadata(self.root, ["0"], fmt=FormatV03(), axes=axes)

0 comments on commit 0c71fbe

Please sign in to comment.