Skip to content
Merged
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
2 changes: 2 additions & 0 deletions changes/2859.removal.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The ``Store.set_partial_writes`` method, which was not used by Zarr-Python, has been removed.
``store.supports_partial_writes`` is now always ``False``.
26 changes: 6 additions & 20 deletions src/zarr/abc/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
from asyncio import gather
from dataclasses import dataclass
from itertools import starmap
from typing import TYPE_CHECKING, Protocol, runtime_checkable
from typing import TYPE_CHECKING, Literal, Protocol, runtime_checkable

if TYPE_CHECKING:
from collections.abc import AsyncGenerator, AsyncIterator, Iterable
from types import TracebackType
from typing import Any, Self, TypeAlias

from zarr.core.buffer import Buffer, BufferPrototype
from zarr.core.common import BytesLike

__all__ = ["ByteGetter", "ByteSetter", "Store", "set_or_delete"]

Expand Down Expand Up @@ -310,25 +309,12 @@ async def delete(self, key: str) -> None:
...

@property
@abstractmethod
def supports_partial_writes(self) -> bool:
"""Does the store support partial writes?"""
...

@abstractmethod
async def set_partial_values(
self, key_start_values: Iterable[tuple[str, int, BytesLike]]
) -> None:
"""Store values at a given key, starting at byte range_start.
def supports_partial_writes(self) -> Literal[False]:
"""Does the store support partial writes?

Parameters
----------
key_start_values : list[tuple[str, int, BytesLike]]
set of key, range_start, values triples, a key may occur multiple times with different
range_starts, range_starts (considering the length of the respective values) must not
specify overlapping ranges for the same key
Partial writes are no longer used by Zarr, so this is always false.
"""
...
return False

@property
@abstractmethod
Expand Down Expand Up @@ -499,7 +485,7 @@ async def get(
self, prototype: BufferPrototype, byte_range: ByteRequest | None = None
) -> Buffer | None: ...

async def set(self, value: Buffer, byte_range: ByteRequest | None = None) -> None: ...
async def set(self, value: Buffer) -> None: ...

async def delete(self) -> None: ...

Expand Down
11 changes: 1 addition & 10 deletions src/zarr/storage/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,24 +163,15 @@ async def get(
prototype = default_buffer_prototype()
return await self.store.get(self.path, prototype=prototype, byte_range=byte_range)

async def set(self, value: Buffer, byte_range: ByteRequest | None = None) -> None:
async def set(self, value: Buffer) -> None:
"""
Write bytes to the store.

Parameters
----------
value : Buffer
The buffer to write.
byte_range : ByteRequest, optional
The range of bytes to write. If None, the entire buffer is written.

Raises
------
NotImplementedError
If `byte_range` is not None, because Store.set does not support partial writes yet.
"""
if byte_range is not None:
raise NotImplementedError("Store.set does not have partial writes yet")
await self.store.set(self.path, value)

async def delete(self) -> None:
Expand Down
9 changes: 0 additions & 9 deletions src/zarr/storage/_fsspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
from fsspec.mapping import FSMap

from zarr.core.buffer import BufferPrototype
from zarr.core.common import BytesLike


ALLOWED_EXCEPTIONS: tuple[type[Exception], ...] = (
Expand Down Expand Up @@ -90,7 +89,6 @@ class FsspecStore(Store):
allowed_exceptions
supports_writes
supports_deletes
supports_partial_writes
supports_listing

Raises
Expand All @@ -114,7 +112,6 @@ class FsspecStore(Store):
# based on FSSpec
supports_writes: bool = True
supports_deletes: bool = True
supports_partial_writes: bool = False
supports_listing: bool = True

fs: AsyncFileSystem
Expand Down Expand Up @@ -418,12 +415,6 @@ async def get_partial_values(

return [None if isinstance(r, Exception) else prototype.buffer.from_bytes(r) for r in res]

async def set_partial_values(
self, key_start_values: Iterable[tuple[str, int, BytesLike]]
) -> None:
# docstring inherited
raise NotImplementedError

async def list(self) -> AsyncIterator[str]:
# docstring inherited
allfiles = await self.fs._find(self.path, detail=False, withdirs=False)
Expand Down
33 changes: 4 additions & 29 deletions src/zarr/storage/_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,23 +77,12 @@ def _atomic_write(
raise


def _put(
path: Path,
value: Buffer,
start: int | None = None,
exclusive: bool = False,
) -> int | None:
def _put(path: Path, value: Buffer, exclusive: bool = False) -> int:
path.parent.mkdir(parents=True, exist_ok=True)
# write takes any object supporting the buffer protocol
view = value.as_buffer_like()
if start is not None:
with path.open("r+b") as f:
f.seek(start)
f.write(view)
return None
else:
with _atomic_write(path, "wb", exclusive=exclusive) as f:
return f.write(view)
with _atomic_write(path, "wb", exclusive=exclusive) as f:
return f.write(view)


class LocalStore(Store):
Expand All @@ -111,14 +100,12 @@ class LocalStore(Store):
----------
supports_writes
supports_deletes
supports_partial_writes
supports_listing
root
"""

supports_writes: bool = True
supports_deletes: bool = True
supports_partial_writes: bool = True
supports_listing: bool = True

root: Path
Expand Down Expand Up @@ -253,19 +240,7 @@ async def _set(self, key: str, value: Buffer, exclusive: bool = False) -> None:
f"LocalStore.set(): `value` must be a Buffer instance. Got an instance of {type(value)} instead."
)
path = self.root / key
await asyncio.to_thread(_put, path, value, start=None, exclusive=exclusive)

async def set_partial_values(
self, key_start_values: Iterable[tuple[str, int, bytes | bytearray | memoryview]]
) -> None:
# docstring inherited
self._check_writable()
args = []
for key, start, value in key_start_values:
assert isinstance(key, str)
path = self.root / key
args.append((_put, path, value, start))
await concurrent_map(args, asyncio.to_thread, limit=None) # TODO: fix limit
await asyncio.to_thread(_put, path, value, exclusive=exclusive)

async def delete(self, key: str) -> None:
"""
Expand Down
13 changes: 0 additions & 13 deletions src/zarr/storage/_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,6 @@ def supports_deletes(self) -> bool:
with self.log():
return self._store.supports_deletes

@property
def supports_partial_writes(self) -> bool:
with self.log():
return self._store.supports_partial_writes

@property
def supports_listing(self) -> bool:
with self.log():
Expand Down Expand Up @@ -207,14 +202,6 @@ async def delete(self, key: str) -> None:
with self.log(key):
return await self._store.delete(key=key)

async def set_partial_values(
self, key_start_values: Iterable[tuple[str, int, bytes | bytearray | memoryview]]
) -> None:
# docstring inherited
keys = ",".join([k[0] for k in key_start_values])
with self.log(keys):
return await self._store.set_partial_values(key_start_values=key_start_values)

async def list(self) -> AsyncGenerator[str, None]:
# docstring inherited
with self.log():
Expand Down
8 changes: 0 additions & 8 deletions src/zarr/storage/_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,11 @@ class MemoryStore(Store):
----------
supports_writes
supports_deletes
supports_partial_writes
supports_listing
"""

supports_writes: bool = True
supports_deletes: bool = True
supports_partial_writes: bool = True
supports_listing: bool = True

_store_dict: MutableMapping[str, Buffer]
Expand Down Expand Up @@ -143,12 +141,6 @@ async def delete(self, key: str) -> None:
except KeyError:
logger.debug("Key %s does not exist.", key)

async def set_partial_values(
self, key_start_values: Iterable[tuple[str, int, bytes | bytearray | memoryview[int]]]
) -> None:
# docstring inherited
raise NotImplementedError

async def list(self) -> AsyncIterator[str]:
# docstring inherited
for key in self._store_dict:
Expand Down
12 changes: 0 additions & 12 deletions src/zarr/storage/_obstore.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from obstore.store import ObjectStore as _UpstreamObjectStore

from zarr.core.buffer import Buffer, BufferPrototype
from zarr.core.common import BytesLike

__all__ = ["ObjectStore"]

Expand Down Expand Up @@ -196,17 +195,6 @@ async def delete(self, key: str) -> None:
with contextlib.suppress(FileNotFoundError):
await obs.delete_async(self.store, key)

@property
def supports_partial_writes(self) -> bool:
# docstring inherited
return False

async def set_partial_values(
self, key_start_values: Iterable[tuple[str, int, BytesLike]]
) -> None:
# docstring inherited
raise NotImplementedError

@property
def supports_listing(self) -> bool:
# docstring inherited
Expand Down
10 changes: 0 additions & 10 deletions src/zarr/storage/_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

from zarr.abc.store import ByteRequest
from zarr.core.buffer import Buffer, BufferPrototype
from zarr.core.common import BytesLike

from zarr.abc.store import Store

Expand Down Expand Up @@ -119,15 +118,6 @@ def supports_deletes(self) -> bool:
async def delete(self, key: str) -> None:
await self._store.delete(key)

@property
def supports_partial_writes(self) -> bool:
return self._store.supports_partial_writes

async def set_partial_values(
self, key_start_values: Iterable[tuple[str, int, BytesLike]]
) -> None:
return await self._store.set_partial_values(key_start_values)

@property
def supports_listing(self) -> bool:
return self._store.supports_listing
Expand Down
7 changes: 0 additions & 7 deletions src/zarr/storage/_zip.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ class ZipStore(Store):
allowed_exceptions
supports_writes
supports_deletes
supports_partial_writes
supports_listing
path
compression
Expand All @@ -57,7 +56,6 @@ class ZipStore(Store):

supports_writes: bool = True
supports_deletes: bool = False
supports_partial_writes: bool = False
supports_listing: bool = True

path: Path
Expand Down Expand Up @@ -222,11 +220,6 @@ async def set(self, key: str, value: Buffer) -> None:
with self._lock:
self._set(key, value)

async def set_partial_values(
self, key_start_values: Iterable[tuple[str, int, bytes | bytearray | memoryview[int]]]
) -> None:
raise NotImplementedError

async def set_if_not_exists(self, key: str, value: Buffer) -> None:
self._check_writable()
with self._lock:
Expand Down
7 changes: 0 additions & 7 deletions src/zarr/testing/stateful.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,17 +467,10 @@ def list_dir(self, prefix: str) -> None:
def list_prefix(self, prefix: str) -> None:
raise NotImplementedError

def set_partial_values(self, key_start_values: Any) -> None:
raise NotImplementedError

@property
def supports_listing(self) -> bool:
return self.store.supports_listing

@property
def supports_partial_writes(self) -> bool:
return self.supports_partial_writes

@property
def supports_writes(self) -> bool:
return self.store.supports_writes
Expand Down
4 changes: 2 additions & 2 deletions src/zarr/testing/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ def test_store_repr(self, store: S) -> None: ...
@abstractmethod
def test_store_supports_writes(self, store: S) -> None: ...

@abstractmethod
def test_store_supports_partial_writes(self, store: S) -> None: ...
def test_store_supports_partial_writes(self, store: S) -> None:
assert not store.supports_partial_writes

@abstractmethod
def test_store_supports_listing(self, store: S) -> None: ...
Expand Down
3 changes: 0 additions & 3 deletions tests/test_store/test_fsspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,6 @@ def test_store_repr(self, store: FsspecStore) -> None:
def test_store_supports_writes(self, store: FsspecStore) -> None:
assert store.supports_writes

def test_store_supports_partial_writes(self, store: FsspecStore) -> None:
assert not store.supports_partial_writes

def test_store_supports_listing(self, store: FsspecStore) -> None:
assert store.supports_listing

Expand Down
3 changes: 0 additions & 3 deletions tests/test_store/test_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ def test_store_repr(self, store: LocalStore) -> None:
def test_store_supports_writes(self, store: LocalStore) -> None:
assert store.supports_writes

def test_store_supports_partial_writes(self, store: LocalStore) -> None:
assert store.supports_partial_writes

def test_store_supports_listing(self, store: LocalStore) -> None:
assert store.supports_listing

Expand Down
3 changes: 0 additions & 3 deletions tests/test_store/test_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ def store(self, store_kwargs: str | dict[str, Buffer] | None) -> LoggingStore:
def test_store_supports_writes(self, store: LoggingStore) -> None:
assert store.supports_writes

def test_store_supports_partial_writes(self, store: LoggingStore) -> None:
assert store.supports_partial_writes

def test_store_supports_listing(self, store: LoggingStore) -> None:
assert store.supports_listing

Expand Down
6 changes: 0 additions & 6 deletions tests/test_store/test_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ def test_store_supports_writes(self, store: MemoryStore) -> None:
def test_store_supports_listing(self, store: MemoryStore) -> None:
assert store.supports_listing

def test_store_supports_partial_writes(self, store: MemoryStore) -> None:
assert store.supports_partial_writes

async def test_list_prefix(self, store: MemoryStore) -> None:
assert True

Expand Down Expand Up @@ -115,9 +112,6 @@ def test_store_supports_writes(self, store: GpuMemoryStore) -> None:
def test_store_supports_listing(self, store: GpuMemoryStore) -> None:
assert store.supports_listing

def test_store_supports_partial_writes(self, store: GpuMemoryStore) -> None:
assert store.supports_partial_writes

async def test_list_prefix(self, store: GpuMemoryStore) -> None:
assert True

Expand Down
Loading
Loading