Skip to content

Commit 327c5d2

Browse files
committed
Add suffix detection in make_store_path to open zip stores from path - add test
1 parent 96c9677 commit 327c5d2

File tree

2 files changed

+40
-3
lines changed

2 files changed

+40
-3
lines changed

src/zarr/storage/_common.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from zarr.storage._local import LocalStore
1212
from zarr.storage._memory import MemoryStore
1313
from zarr.storage._utils import normalize_path
14+
from zarr.storage._zip import ZipStore
1415

1516
if TYPE_CHECKING:
1617
from zarr.core.buffer import BufferPrototype
@@ -241,7 +242,8 @@ async def make_store_path(
241242
`StoreLike` object can be a `Store`, `StorePath`, `Path`, `str`, or `dict[str, Buffer]`.
242243
If the `StoreLike` object is a Store or `StorePath`, it is converted to a
243244
`StorePath` object. If the `StoreLike` object is a Path or str, it is converted
244-
to a LocalStore object and then to a `StorePath` object. If the `StoreLike`
245+
to a LocalStore object and then to a `StorePath` object, unless it has a .zip suffix,
246+
in which case a ZipStore object is used to create the `StorePath`. If the `StoreLike`
245247
object is a dict[str, Buffer], it is converted to a `MemoryStore` object and
246248
then to a `StorePath` object.
247249
@@ -295,6 +297,8 @@ async def make_store_path(
295297
store = store_like
296298
elif store_like is None:
297299
store = await MemoryStore.open(read_only=_read_only)
300+
elif isinstance(store_like, Path) and store_like.suffix == ".zip":
301+
store = await ZipStore.open(path=store_like, mode=mode or "r")
298302
elif isinstance(store_like, Path):
299303
store = await LocalStore.open(root=store_like, read_only=_read_only)
300304
elif isinstance(store_like, str):
@@ -305,6 +309,8 @@ async def make_store_path(
305309
store = FsspecStore.from_url(
306310
store_like, storage_options=storage_options, read_only=_read_only
307311
)
312+
elif store_like.endswith(".zip"):
313+
store = await ZipStore.open(path=Path(store_like), mode=mode or "r")
308314
else:
309315
store = await LocalStore.open(root=Path(store_like), read_only=_read_only)
310316
elif isinstance(store_like, dict):

tests/test_store/test_core.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import tempfile
22
from pathlib import Path
33

4+
import numpy as np
45
import pytest
56
from _pytest.compat import LEGACY_PATH
67

7-
from zarr import Group
8+
from zarr import Group, open_group
89
from zarr.core.common import AccessModeLiteral, ZarrFormat
9-
from zarr.storage import FsspecStore, LocalStore, MemoryStore, StoreLike, StorePath
10+
from zarr.storage import FsspecStore, LocalStore, MemoryStore, StoreLike, StorePath, ZipStore
1011
from zarr.storage._common import contains_array, contains_group, make_store_path
1112
from zarr.storage._utils import normalize_path
1213

@@ -83,6 +84,36 @@ async def test_make_store_path_local(
8384
assert store_path.read_only == (mode == "r")
8485

8586

87+
@pytest.mark.parametrize("store_type", [str, Path])
88+
@pytest.mark.parametrize("mode", ["r", "w"])
89+
async def test_make_store_path_zip_path(
90+
tmpdir: LEGACY_PATH,
91+
store_type: type[str] | type[Path] | type[LocalStore],
92+
mode: AccessModeLiteral,
93+
) -> None:
94+
"""
95+
Test that make_store_path creates a ZipStore given a path ending in .zip
96+
"""
97+
zippath = Path(tmpdir) / "zarr.zip"
98+
store_like = store_type(str(zippath))
99+
100+
if mode == "r":
101+
store = ZipStore(zippath, mode="w")
102+
root = open_group(store=store, mode="w")
103+
data = np.arange(10000, dtype=np.uint16).reshape(100, 100)
104+
z = root.create_array(
105+
shape=data.shape, chunks=(10, 10), name="foo", dtype=np.uint16, fill_value=99
106+
)
107+
z[:] = data
108+
store.close()
109+
110+
store_path = await make_store_path(store_like, mode=mode)
111+
assert isinstance(store_path.store, ZipStore)
112+
assert Path(store_path.store.path) == zippath
113+
assert store_path.path == normalize_path("")
114+
assert store_path.read_only == (mode == "r")
115+
116+
86117
@pytest.mark.parametrize("path", [None, "", "bar"])
87118
@pytest.mark.parametrize("mode", ["r", "w"])
88119
async def test_make_store_path_store_path(

0 commit comments

Comments
 (0)