5
5
import time
6
6
from collections import defaultdict
7
7
from contextlib import contextmanager
8
- from typing import TYPE_CHECKING , Self
8
+ from typing import TYPE_CHECKING , Any , Self
9
9
10
10
from zarr .abc .store import AccessMode , ByteRangeRequest , Store
11
11
from zarr .core .buffer import Buffer
@@ -57,17 +57,24 @@ def _default_handler(self) -> logging.Handler:
57
57
return handler
58
58
59
59
@contextmanager
60
- def log (self ) -> Generator [None , None , None ]:
60
+ def log (self , hint : Any = "" ) -> Generator [None , None , None ]:
61
+ """Context manager to log method calls
62
+
63
+ Each call to the wrapped store is logged to the configured logger and added to
64
+ the counter dict.
65
+ """
61
66
method = inspect .stack ()[2 ].function
62
67
op = f"{ type (self ._store ).__name__ } .{ method } "
68
+ if hint :
69
+ op += f"({ hint } )"
63
70
self .logger .info (f"Calling { op } " )
64
71
start_time = time .time ()
65
72
try :
66
73
self .counter [method ] += 1
67
74
yield
68
75
finally :
69
76
end_time = time .time ()
70
- self .logger .info (f"Finished { op } in { end_time - start_time :.2f} seconds " )
77
+ self .logger .info (f"Finished { op } [ { end_time - start_time :.2f} s] " )
71
78
72
79
@property
73
80
def supports_writes (self ) -> bool :
@@ -95,10 +102,15 @@ def _mode(self) -> AccessMode: # type: ignore[override]
95
102
return self ._store ._mode
96
103
97
104
@property
98
- def _is_open (self ) -> bool : # type: ignore[override]
105
+ def _is_open (self ) -> bool :
99
106
with self .log ():
100
107
return self ._store ._is_open
101
108
109
+ @_is_open .setter
110
+ def _is_open (self , value : bool ) -> None :
111
+ with self .log (value ):
112
+ self ._store ._is_open = value
113
+
102
114
async def _open (self ) -> None :
103
115
with self .log ():
104
116
return await self ._store ._open ()
@@ -122,7 +134,7 @@ def __repr__(self) -> str:
122
134
return f"LoggingStore({ repr (self ._store )!r} )"
123
135
124
136
def __eq__ (self , other : object ) -> bool :
125
- with self .log ():
137
+ with self .log (other ):
126
138
return self ._store == other
127
139
128
140
async def get (
@@ -131,56 +143,69 @@ async def get(
131
143
prototype : BufferPrototype ,
132
144
byte_range : tuple [int | None , int | None ] | None = None ,
133
145
) -> Buffer | None :
134
- with self .log ():
146
+ # docstring inherited
147
+ with self .log (key ):
135
148
return await self ._store .get (key = key , prototype = prototype , byte_range = byte_range )
136
149
137
150
async def get_partial_values (
138
151
self ,
139
152
prototype : BufferPrototype ,
140
153
key_ranges : Iterable [tuple [str , ByteRangeRequest ]],
141
154
) -> list [Buffer | None ]:
142
- with self .log ():
155
+ # docstring inherited
156
+ keys = "," .join ([k [0 ] for k in key_ranges ])
157
+ with self .log (keys ):
143
158
return await self ._store .get_partial_values (prototype = prototype , key_ranges = key_ranges )
144
159
145
160
async def exists (self , key : str ) -> bool :
146
- with self .log ():
161
+ # docstring inherited
162
+ with self .log (key ):
147
163
return await self ._store .exists (key )
148
164
149
165
async def set (self , key : str , value : Buffer ) -> None :
150
- with self .log ():
166
+ # docstring inherited
167
+ with self .log (key ):
151
168
return await self ._store .set (key = key , value = value )
152
169
153
170
async def set_if_not_exists (self , key : str , value : Buffer ) -> None :
154
- with self .log ():
171
+ # docstring inherited
172
+ with self .log (key ):
155
173
return await self ._store .set_if_not_exists (key = key , value = value )
156
174
157
175
async def delete (self , key : str ) -> None :
158
- with self .log ():
176
+ # docstring inherited
177
+ with self .log (key ):
159
178
return await self ._store .delete (key = key )
160
179
161
180
async def set_partial_values (
162
181
self , key_start_values : Iterable [tuple [str , int , bytes | bytearray | memoryview ]]
163
182
) -> None :
164
- with self .log ():
183
+ # docstring inherited
184
+ keys = "," .join ([k [0 ] for k in key_start_values ])
185
+ with self .log (keys ):
165
186
return await self ._store .set_partial_values (key_start_values = key_start_values )
166
187
167
188
async def list (self ) -> AsyncGenerator [str , None ]:
189
+ # docstring inherited
168
190
with self .log ():
169
191
async for key in self ._store .list ():
170
192
yield key
171
193
172
194
async def list_prefix (self , prefix : str ) -> AsyncGenerator [str , None ]:
173
- with self .log ():
195
+ # docstring inherited
196
+ with self .log (prefix ):
174
197
async for key in self ._store .list_prefix (prefix = prefix ):
175
198
yield key
176
199
177
200
async def list_dir (self , prefix : str ) -> AsyncGenerator [str , None ]:
178
- with self .log ():
201
+ # docstring inherited
202
+ with self .log (prefix ):
179
203
async for key in self ._store .list_dir (prefix = prefix ):
180
204
yield key
181
205
182
206
def with_mode (self , mode : AccessModeLiteral ) -> Self :
183
- with self .log ():
207
+ # docstring inherited
208
+ with self .log (mode ):
184
209
return type (self )(
185
210
self ._store .with_mode (mode ),
186
211
log_level = self .log_level ,
0 commit comments