Repository: ome/ome-zarr-py

Issue:
[test-bot] pip install --pre is failing
The Test pre-releases workflow failed on 2024-11-26 23:06 UTC

The most recent failing test was on windows-latest py py311
with commit: fbf0a2ec6ce562e21c9bcdab860e250740fe7526

Full run: https://github.com/ome/ome-zarr-py/actions/runs/12040502840

(This post will be updated if another test fails, as long as this issue remains open.)

Discussion:
@jluethi: Also just ran into this and noticed that it depends on the version of fsspec: It was working fine for me on prior versions (like the one just before, fsspec==2023.6.0), but breaks with fsspec==2023.9.0@blowekamp: I have also encountered errors with the `fsspec==2023.9.0` update and having to exclude the versions for my dependencies. Here is a small example to reproduce the error we have encountered:

```
from ome_zarr.io import parse_url
from ome_zarr.writer import write_image
from ome_zarr.scale import Scaler
import numpy as np
import zarr
path = "test.zarr"
data = np.ndarray((10,10))
store = parse_url(path, mode="w").store
root = zarr.group(store=store)
scaler = Scaler(max_layer=0, method="nearest")
 write_image(image=data, axes="yx", group=root, scaler=scaler)
write_image(image=data, group=root)
```

Solution patch:
diff --git a/docs/requirements.txt b/docs/requirements.txt
index ee42174..43edccc 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1,6 +1,6 @@
 sphinx==7.1.2
 sphinx-rtd-theme==3.0.2
-fsspec==2023.6.0
+fsspec
 zarr
 dask
 numpy
diff --git a/ome_zarr/scale.py b/ome_zarr/scale.py
index 2ed3b65..deac331 100644
--- a/ome_zarr/scale.py
+++ b/ome_zarr/scale.py
@@ -39,6 +39,21 @@ class Scaler:
     choices. These values can be returned by the
     :func:`~ome_zarr.scale.Scaler.methods` method.
 
+    Attributes:
+        copy_metadata:
+            If `True`, copy Zarr attributes from the input array to the new group.
+        downscale:
+            Downscaling factor.
+        in_place:
+            Does not do anything.
+        labeled:
+            If `True`, check that the values in the downsampled levels are a subset
+            of the values found in the input array.
+        max_layer:
+            The maximum number of downsampled layers to create.
+        method:
+            Downsampling method
+
     >>> import numpy as np
     >>> data = np.zeros((1, 1, 1, 64, 64))
     >>> scaler = Scaler()
diff --git a/ome_zarr/utils.py b/ome_zarr/utils.py
index 086ede3..c929c28 100644
--- a/ome_zarr/utils.py
+++ b/ome_zarr/utils.py
@@ -129,7 +129,9 @@ def download(input_path: str, output_dir: str = ".") -> None:
                     for dataset, data in reversed(list(zip(datasets, resolutions))):
                         LOGGER.info("resolution %s...", dataset)
                         with pbar:
-                            data.to_zarr(str(target_path / dataset))
+                            data.to_zarr(
+                                str(target_path / dataset), dimension_separator="/"
+                            )
             else:
                 # Assume a group that needs metadata, like labels
                 zarr.group(str(target_path))
diff --git a/pyproject.toml b/pyproject.toml
index 2327a52..975bf5c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -21,7 +21,7 @@ dependencies = [
     "dask",
     "distributed",
     "zarr>=2.8.1,<3",
-    "fsspec[s3]>=0.8,!=2021.07.0",
+    "fsspec[s3]>=0.8,!=2021.07.0,!=2023.9.0",
     # See https://github.com/fsspec/filesystem_spec/issues/819
     "aiohttp<4",
     "requests",


Test patch:
diff --git a/tests/test_cli.py b/tests/test_cli.py
index cd60e6c..b38aba4 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -8,6 +8,16 @@ from ome_zarr.cli import main
 from ome_zarr.utils import strip_common_prefix
 
 
+def directory_items(directory: Path):
+    """
+    Get all items (files and folders) in a directory, relative to that directory.
+    """
+    if not directory.is_dir():
+        raise ValueError(f"{directory} is not a directory")
+
+    return sorted([p.relative_to(directory) for p in directory.glob("*")])
+
+
 class TestCli:
     @pytest.fixture(autouse=True)
     def initdir(self, tmpdir):
@@ -40,6 +50,24 @@ class TestCli:
         main(["download", filename, f"--output={out}"])
         main(["info", f"{out}/{basename}"])
 
+        assert directory_items(Path(out) / "data-3") == [
+            Path(".zattrs"),
+            Path(".zgroup"),
+            Path("0"),
+            Path("1"),
+            Path("2"),
+            Path("3"),
+            Path("4"),
+            Path("labels"),
+        ]
+
+        assert directory_items(Path(out) / "data-3" / "1") == [
+            Path(".zarray"),
+            Path("0"),
+            Path("1"),
+            Path("2"),
+        ]
+
     def test_s3_info(self, s3_address):
         main(["info", s3_address])