|
17 | 17 | from zarr.errors import ZarrUserWarning |
18 | 18 | from zarr.storage import FsspecStore |
19 | 19 | from zarr.storage._fsspec import _make_async |
| 20 | +from zarr.storage._utils import normalize_path |
20 | 21 | from zarr.testing.store import StoreTests |
21 | 22 |
|
22 | 23 | if TYPE_CHECKING: |
@@ -286,6 +287,27 @@ def array_roundtrip(store: FsspecStore) -> None: |
286 | 287 | np.testing.assert_array_equal(arr[:], data) |
287 | 288 |
|
288 | 289 |
|
| 290 | +@pytest.mark.skipif( |
| 291 | + parse_version(fsspec.__version__) < parse_version("2024.12.0"), |
| 292 | + reason="No AsyncFileSystemWrapper", |
| 293 | +) |
| 294 | +@pytest.mark.parametrize("path", ["", "/", "//", "foo", "foo/", "/foo", "/foo/", "//foo//"]) |
| 295 | +def test_fsspec_store_path_normalization(path: str) -> None: |
| 296 | + """`FsspecStore.path` is normalized to the canonical form, matching |
| 297 | + `normalize_path`, regardless of the surface representation the caller |
| 298 | + supplies. |
| 299 | +
|
| 300 | + Regression test for https://github.com/zarr-developers/zarr-python/issues/3922 |
| 301 | + -- when a caller passed `path="/"` the leading slash flowed through |
| 302 | + unmodified to subsequent `_join_paths([self.path, key])` calls, producing |
| 303 | + `"//key"` and missing the underlying object. |
| 304 | + """ |
| 305 | + sync_fs = fsspec.filesystem("memory") |
| 306 | + fs = _make_async(sync_fs) |
| 307 | + store = FsspecStore(fs=fs, path=path) |
| 308 | + assert store.path == normalize_path(path) |
| 309 | + |
| 310 | + |
289 | 311 | @pytest.mark.skipif( |
290 | 312 | parse_version(fsspec.__version__) < parse_version("2024.12.0"), |
291 | 313 | reason="No AsyncFileSystemWrapper", |
|
0 commit comments