Skip to content

Commit ca9bd3e

Browse files
nuglifeleojiLeo Jid-v-b
authored
fix: auto-open ZipStore in list(), list_dir() and exists() (#3855)
ZipStore._get() and ._set() already auto-open the zip file when called without a prior open(). Apply the same pattern to list(), list_dir(), and exists() so that all store methods behave consistently when the store has not been explicitly opened. Closes #3846 Made-with: Cursor Co-authored-by: Leo Ji <nuglifeleoji@gmail.com> Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
1 parent dd86ac7 commit ca9bd3e

File tree

3 files changed

+32
-0
lines changed

3 files changed

+32
-0
lines changed

changes/3846.bugfix.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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()`.

src/zarr/storage/_zip.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ async def delete(self, key: str) -> None:
245245

246246
async def exists(self, key: str) -> bool:
247247
# docstring inherited
248+
if not self._is_open:
249+
self._sync_open()
248250
with self._lock:
249251
try:
250252
self._zf.getinfo(key)
@@ -255,6 +257,8 @@ async def exists(self, key: str) -> bool:
255257

256258
async def list(self) -> AsyncIterator[str]:
257259
# docstring inherited
260+
if not self._is_open:
261+
self._sync_open()
258262
with self._lock:
259263
for key in self._zf.namelist():
260264
yield key
@@ -267,6 +271,8 @@ async def list_prefix(self, prefix: str) -> AsyncIterator[str]:
267271

268272
async def list_dir(self, prefix: str) -> AsyncIterator[str]:
269273
# docstring inherited
274+
if not self._is_open:
275+
self._sync_open()
270276
prefix = prefix.rstrip("/")
271277

272278
keys = self._zf.namelist()

tests/test_store/test_zip.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,31 @@ def test_externally_zipped_store(self, tmp_path: Path) -> None:
139139
assert isinstance(group := zipped["foo"], Group)
140140
assert list(group.keys()) == list(group.keys())
141141

142+
async def test_list_without_explicit_open(self, tmp_path: Path) -> None:
143+
# ZipStore.list(), list_dir(), and exists() should auto-open
144+
# the zip file just like _get() and _set() do.
145+
zip_path = tmp_path / "data.zip"
146+
zarr_path = tmp_path / "foo.zarr"
147+
root = zarr.open_group(store=zarr_path, mode="w")
148+
root["x"] = np.array([1, 2, 3])
149+
shutil.make_archive(str(zarr_path), "zip", zarr_path)
150+
shutil.move(str(zarr_path) + ".zip", zip_path)
151+
152+
store = ZipStore(zip_path, mode="r")
153+
assert not store._is_open
154+
155+
keys = [k async for k in store.list()]
156+
assert len(keys) > 0
157+
158+
store2 = ZipStore(zip_path, mode="r")
159+
assert not store2._is_open
160+
assert await store2.exists(keys[0])
161+
162+
store3 = ZipStore(zip_path, mode="r")
163+
assert not store3._is_open
164+
dir_keys = [k async for k in store3.list_dir("")]
165+
assert len(dir_keys) > 0
166+
142167
async def test_move(self, tmp_path: Path) -> None:
143168
origin = tmp_path / "origin.zip"
144169
destination = tmp_path / "some_folder" / "destination.zip"

0 commit comments

Comments
 (0)