Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions changes/3846.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix `ZipStore.list()`, `list_dir()`, and `exists()` to auto-open the zip file when called before `open()`, consistent with the existing behavior of `get()` and `set()`.
6 changes: 6 additions & 0 deletions src/zarr/storage/_zip.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ async def delete(self, key: str) -> None:

async def exists(self, key: str) -> bool:
# docstring inherited
if not self._is_open:
self._sync_open()
with self._lock:
try:
self._zf.getinfo(key)
Expand All @@ -255,6 +257,8 @@ async def exists(self, key: str) -> bool:

async def list(self) -> AsyncIterator[str]:
# docstring inherited
if not self._is_open:
self._sync_open()
with self._lock:
for key in self._zf.namelist():
yield key
Expand All @@ -267,6 +271,8 @@ async def list_prefix(self, prefix: str) -> AsyncIterator[str]:

async def list_dir(self, prefix: str) -> AsyncIterator[str]:
# docstring inherited
if not self._is_open:
self._sync_open()
prefix = prefix.rstrip("/")

keys = self._zf.namelist()
Expand Down
25 changes: 25 additions & 0 deletions tests/test_store/test_zip.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,31 @@ def test_externally_zipped_store(self, tmp_path: Path) -> None:
assert isinstance(group := zipped["foo"], Group)
assert list(group.keys()) == list(group.keys())

async def test_list_without_explicit_open(self, tmp_path: Path) -> None:
# ZipStore.list(), list_dir(), and exists() should auto-open
# the zip file just like _get() and _set() do.
zip_path = tmp_path / "data.zip"
zarr_path = tmp_path / "foo.zarr"
root = zarr.open_group(store=zarr_path, mode="w")
root["x"] = np.array([1, 2, 3])
shutil.make_archive(str(zarr_path), "zip", zarr_path)
shutil.move(str(zarr_path) + ".zip", zip_path)

store = ZipStore(zip_path, mode="r")
assert not store._is_open

keys = [k async for k in store.list()]
assert len(keys) > 0

store2 = ZipStore(zip_path, mode="r")
assert not store2._is_open
assert await store2.exists(keys[0])

store3 = ZipStore(zip_path, mode="r")
assert not store3._is_open
dir_keys = [k async for k in store3.list_dir("")]
assert len(dir_keys) > 0

async def test_move(self, tmp_path: Path) -> None:
origin = tmp_path / "origin.zip"
destination = tmp_path / "some_folder" / "destination.zip"
Expand Down
Loading