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
12 changes: 12 additions & 0 deletions src/zarr/storage/_zip.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,18 @@ def _sync_open(self) -> None:

self._lock = threading.RLock()

if self._zmode == "r" and not self.path.exists():
# zipfile.ZipFile requires the file to exist in read mode,
# but other stores can be opened in read mode without IO.
# create an empty zip file so that the store can be opened.
with zipfile.ZipFile(
self.path,
mode="w",
compression=self.compression,
allowZip64=self.allowZip64,
):
pass

self._zf = zipfile.ZipFile(
self.path,
mode=self._zmode,
Expand Down
18 changes: 18 additions & 0 deletions tests/test_store/test_zip.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,21 @@ async def test_move(self, tmp_path: Path) -> None:
assert destination.exists()
assert not origin.exists()
assert np.array_equal(array[...], np.arange(10))

async def test_fresh_zip_store_read_mode(self, tmp_path: Path) -> None:
# See: https://github.com/zarr-developers/zarr-python/issues/2450
# A fresh ZipStore should be openable in read mode without error.
zip_path = tmp_path / "fresh.zip"
assert not zip_path.exists()

store = await ZipStore.open(path=zip_path, mode="r")
assert store._is_open
assert store.read_only

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

assert await store.get("nonexistent", default_buffer_prototype()) is None
assert not await store.exists("nonexistent")

store.close()
Loading