33from abc import ABC , abstractmethod
44from asyncio import gather
55from itertools import starmap
6- from typing import TYPE_CHECKING , NamedTuple , Protocol , runtime_checkable
6+ from typing import TYPE_CHECKING , Literal , Protocol , runtime_checkable
77
88if TYPE_CHECKING :
99 from collections .abc import AsyncGenerator , Iterable
1010 from types import TracebackType
1111 from typing import Any , Self , TypeAlias
1212
1313 from zarr .core .buffer import Buffer , BufferPrototype
14- from zarr .core .common import AccessModeLiteral , BytesLike
14+ from zarr .core .common import BytesLike
1515
16- __all__ = ["AccessMode " , "ByteGetter" , "ByteSetter" , "Store" , "set_or_delete" ]
16+ __all__ = ["StoreAccessMode " , "ByteGetter" , "ByteSetter" , "Store" , "set_or_delete" ]
1717
1818ByteRangeRequest : TypeAlias = tuple [int | None , int | None ]
19-
20-
21- class AccessMode (NamedTuple ):
22- """Access mode flags."""
23-
24- str : AccessModeLiteral
25- readonly : bool
26- overwrite : bool
27- create : bool
28- update : bool
29-
30- @classmethod
31- def from_literal (cls , mode : AccessModeLiteral ) -> Self :
32- """
33- Create an AccessMode instance from a literal.
34-
35- Parameters
36- ----------
37- mode : AccessModeLiteral
38- One of 'r', 'r+', 'w', 'w-', 'a'.
39-
40- Returns
41- -------
42- AccessMode
43- The created instance.
44-
45- Raises
46- ------
47- ValueError
48- If mode is not one of 'r', 'r+', 'w', 'w-', 'a'.
49- """
50- if mode in ("r" , "r+" , "a" , "w" , "w-" ):
51- return cls (
52- str = mode ,
53- readonly = mode == "r" ,
54- overwrite = mode == "w" ,
55- create = mode in ("a" , "w" , "w-" ),
56- update = mode in ("r+" , "a" ),
57- )
58- raise ValueError ("mode must be one of 'r', 'r+', 'w', 'w-', 'a'" )
19+ StoreAccessMode = Literal ["r" , "w" ]
5920
6021
6122class Store (ABC ):
6223 """
6324 Abstract base class for Zarr stores.
6425 """
6526
66- _mode : AccessMode
27+ _mode : StoreAccessMode
6728 _is_open : bool
6829
69- def __init__ (self , * args : Any , mode : AccessModeLiteral = "r" , ** kwargs : Any ) -> None :
30+ def __init__ (self , * args : Any , mode : StoreAccessMode = "r" , ** kwargs : Any ) -> None :
7031 self ._is_open = False
71- self ._mode = AccessMode .from_literal (mode )
32+ assert mode in ("r" , "w" )
33+ self ._mode = mode
7234
7335 @classmethod
7436 async def open (cls , * args : Any , ** kwargs : Any ) -> Self :
@@ -112,49 +74,48 @@ async def _open(self) -> None:
11274 ------
11375 ValueError
11476 If the store is already open.
115- FileExistsError
116- If ``mode='w-'`` and the store already exists.
117-
118- Notes
119- -----
120- * When ``mode='w'`` and the store already exists, it will be cleared.
12177 """
12278 if self ._is_open :
12379 raise ValueError ("store is already open" )
124- if self .mode .str == "w" :
125- await self .clear ()
126- elif self .mode .str == "w-" and not await self .empty ():
127- raise FileExistsError ("Store already exists" )
12880 self ._is_open = True
12981
13082 async def _ensure_open (self ) -> None :
13183 """Open the store if it is not already open."""
13284 if not self ._is_open :
13385 await self ._open ()
13486
135- @abstractmethod
136- async def empty (self ) -> bool :
87+ async def empty (self , prefix : str = "" ) -> bool :
13788 """
138- Check if the store is empty.
89+ Check if the directory is empty.
90+
91+ Parameters
92+ ----------
93+ prefix : str
94+ Prefix of keys to check.
13995
14096 Returns
14197 -------
14298 bool
14399 True if the store is empty, False otherwise.
144100 """
145- ...
146101
147- @abstractmethod
102+ if not prefix .endswith ("/" ):
103+ prefix += "/"
104+ async for _ in self .list_prefix (prefix ):
105+ return False
106+ return True
107+
148108 async def clear (self ) -> None :
149109 """
150110 Clear the store.
151111
152112 Remove all keys and values from the store.
153113 """
154- ...
114+ async for key in self .list ():
115+ await self .delete (key )
155116
156117 @abstractmethod
157- def with_mode (self , mode : AccessModeLiteral ) -> Self :
118+ def with_mode (self , mode : StoreAccessMode ) -> Self :
158119 """
159120 Return a new store of the same type pointing to the same location with a new mode.
160121
@@ -163,7 +124,7 @@ def with_mode(self, mode: AccessModeLiteral) -> Self:
163124
164125 Parameters
165126 ----------
166- mode : AccessModeLiteral
127+ mode : StoreAccessMode
167128 The new mode to use.
168129
169130 Returns
@@ -179,14 +140,19 @@ def with_mode(self, mode: AccessModeLiteral) -> Self:
179140 ...
180141
181142 @property
182- def mode (self ) -> AccessMode :
143+ def mode (self ) -> StoreAccessMode :
183144 """Access mode of the store."""
184145 return self ._mode
185146
147+ @property
148+ def readonly (self ) -> bool :
149+ """Is the store read-only?"""
150+ return self .mode == "r"
151+
186152 def _check_writable (self ) -> None :
187153 """Raise an exception if the store is not writable."""
188- if self .mode . readonly :
189- raise ValueError ("store mode does not support writing" )
154+ if self .mode != "w" :
155+ raise ValueError (f "store mode ( { self . mode } ) does not support writing" )
190156
191157 @abstractmethod
192158 def __eq__ (self , value : object ) -> bool :
0 commit comments