Skip to content

Commit e6bb1ae

Browse files
Backport PR #3140: Suppress FileNotFoundError when deleting keys in the obstore adapter (#3180)
Co-authored-by: Lukas Bindreiter <[email protected]>
1 parent 5c10a4f commit e6bb1ae

File tree

3 files changed

+20
-1
lines changed

3 files changed

+20
-1
lines changed

changes/3140.bugfix.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Suppress `FileNotFoundError` when deleting non-existent keys in the `obstore` adapter.
2+
3+
When writing empty chunks (i.e. chunks where all values are equal to the array's fill value) to a zarr array, zarr
4+
will delete those chunks from the underlying store. For zarr arrays backed by the `obstore` adapter, this will potentially
5+
raise a `FileNotFoundError` if the chunk doesn't already exist.
6+
Since whether or not a delete of a non-existing object raises an error depends on the behavior of the underlying store,
7+
suppressing the error in all cases results in consistent behavior across stores, and is also what `zarr` seems to expect
8+
from the store.

src/zarr/storage/_obstore.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,13 @@ async def delete(self, key: str) -> None:
181181
import obstore as obs
182182

183183
self._check_writable()
184-
await obs.delete_async(self.store, key)
184+
185+
# Some obstore stores such as local filesystems, GCP and Azure raise an error
186+
# when deleting a non-existent key, while others such as S3 and in-memory do
187+
# not. We suppress the error to make the behavior consistent across all obstore
188+
# stores. This is also in line with the behavior of the other Zarr store adapters.
189+
with contextlib.suppress(FileNotFoundError):
190+
await obs.delete_async(self.store, key)
185191

186192
@property
187193
def supports_partial_writes(self) -> bool:

src/zarr/testing/store.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,11 @@ async def test_delete_dir(self, store: S) -> None:
349349
assert not await store.exists("foo/zarr.json")
350350
assert not await store.exists("foo/c/0")
351351

352+
async def test_delete_nonexistent_key_does_not_raise(self, store: S) -> None:
353+
if not store.supports_deletes:
354+
pytest.skip("store does not support deletes")
355+
await store.delete("nonexistent_key")
356+
352357
async def test_is_empty(self, store: S) -> None:
353358
assert await store.is_empty("")
354359
await self.set(

0 commit comments

Comments
 (0)