Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
8 changes: 8 additions & 0 deletions changes/3140.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Suppress `FileNotFoundError` when deleting non-existent keys in the `obstore` adapter.

When writing empty chunks (i.e. chunks where all values are equal to the array's fill value) to a zarr array, zarr
will delete those chunks from the underlying store. For zarr arrays backed by the `obstore` adapter, this will potentially
raise a `FileNotFoundError` if the chunk doesn't already exist.
Since whether or not a delete of a non-existing object raises an error depends on the behavior of the underlying store,
suppressing the error in all cases results in consistent behavior across stores, and is also what `zarr` seems to expect
from the store.
10 changes: 9 additions & 1 deletion src/zarr/storage/_obstore.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,17 @@
async def delete(self, key: str) -> None:
# docstring inherited
import obstore as obs
from obstore.exceptions import NotFoundError

Check warning on line 189 in src/zarr/storage/_obstore.py

View check run for this annotation

Codecov / codecov/patch

src/zarr/storage/_obstore.py#L189

Added line #L189 was not covered by tests

self._check_writable()
await obs.delete_async(self.store, key)

# Some stores such as local filesystems, GCP and Azure raise an error
# when deleting a non-existent key, while others such as S3 and in-memory do
# not. We suppress the error to make the behavior consistent across all stores
# currently obstore raises FileNotFoundError, but in the future might raise
# NotFoundError instead, so let's suppress that too
with contextlib.suppress(FileNotFoundError, NotFoundError):
await obs.delete_async(self.store, key)

Check warning on line 199 in src/zarr/storage/_obstore.py

View check run for this annotation

Codecov / codecov/patch

src/zarr/storage/_obstore.py#L198-L199

Added lines #L198 - L199 were not covered by tests

@property
def supports_partial_writes(self) -> bool:
Expand Down
5 changes: 5 additions & 0 deletions src/zarr/testing/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,11 @@
assert not await store.exists("foo/zarr.json")
assert not await store.exists("foo/c/0")

async def test_delete_nonexistent_key_does_not_raise(self, store: S) -> None:
if not store.supports_deletes:
pytest.skip("store does not support deletes")

Check warning on line 406 in src/zarr/testing/store.py

View check run for this annotation

Codecov / codecov/patch

src/zarr/testing/store.py#L406

Added line #L406 was not covered by tests
await store.delete("nonexistent_key")

async def test_is_empty(self, store: S) -> None:
assert await store.is_empty("")
await self.set(
Expand Down