Skip to content

Commit 5183fad

Browse files
committed
Add a new type GetResult to src/zarr/abc/codec.py.
This type is a typeddict that stores information about a completed attempt to fetch a stored resource, e.g. a chunk. Currently, `GetResult` only stores whether the resource was present or missing. We can add more capacity to this type in the future.
1 parent 690c5bb commit 5183fad

File tree

3 files changed

+41
-11
lines changed

3 files changed

+41
-11
lines changed

src/zarr/abc/codec.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from abc import abstractmethod
44
from collections.abc import Mapping
5-
from typing import TYPE_CHECKING, Generic, Protocol, TypeGuard, TypeVar, runtime_checkable
5+
from typing import TYPE_CHECKING, Generic, Literal, Protocol, TypeGuard, TypeVar, runtime_checkable
66

77
from typing_extensions import ReadOnly, TypedDict
88

@@ -32,9 +32,17 @@
3232
"CodecInput",
3333
"CodecOutput",
3434
"CodecPipeline",
35+
"GetResult",
3536
"SupportsSyncCodec",
3637
]
3738

39+
40+
class GetResult(TypedDict):
41+
"""Metadata about a store get operation."""
42+
43+
status: Literal["present", "missing"]
44+
45+
3846
CodecInput = TypeVar("CodecInput", bound=NDBuffer | Buffer)
3947
CodecOutput = TypeVar("CodecOutput", bound=NDBuffer | Buffer)
4048

@@ -433,13 +441,13 @@ async def read(
433441
batch_info: Iterable[tuple[ByteGetter, ArraySpec, SelectorTuple, SelectorTuple, bool]],
434442
out: NDBuffer,
435443
drop_axes: tuple[int, ...] = (),
436-
) -> None:
444+
) -> tuple[GetResult, ...]:
437445
"""Reads chunk data from the store, decodes it and writes it into an output array.
438446
Partial decoding may be utilized if the codecs and stores support it.
439447
440448
Parameters
441449
----------
442-
batch_info : Iterable[tuple[ByteGetter, ArraySpec, SelectorTuple, SelectorTuple]]
450+
batch_info : Iterable[tuple[ByteGetter, ArraySpec, SelectorTuple, SelectorTuple, bool]]
443451
Ordered set of information about the chunks.
444452
The first slice selection determines which parts of the chunk will be fetched.
445453
The second slice selection determines where in the output array the chunk data will be written.
@@ -451,6 +459,11 @@ async def read(
451459
``out``) to the fill value for the array.
452460
453461
out : NDBuffer
462+
463+
Returns
464+
-------
465+
tuple[GetResult, ...]
466+
One result per chunk in ``batch_info``.
454467
"""
455468
...
456469

src/zarr/core/codec_pipeline.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
BytesBytesCodec,
1414
Codec,
1515
CodecPipeline,
16+
GetResult,
1617
)
1718
from zarr.core.common import concurrent_map
1819
from zarr.core.config import config
@@ -251,47 +252,58 @@ async def read_batch(
251252
batch_info: Iterable[tuple[ByteGetter, ArraySpec, SelectorTuple, SelectorTuple, bool]],
252253
out: NDBuffer,
253254
drop_axes: tuple[int, ...] = (),
254-
) -> None:
255+
) -> tuple[GetResult, ...]:
256+
results: list[GetResult] = []
255257
if self.supports_partial_decode:
258+
batch_info_list = list(batch_info)
256259
chunk_array_batch = await self.decode_partial_batch(
257260
[
258261
(byte_getter, chunk_selection, chunk_spec)
259-
for byte_getter, chunk_spec, chunk_selection, *_ in batch_info
262+
for byte_getter, chunk_spec, chunk_selection, *_ in batch_info_list
260263
]
261264
)
262265
for chunk_array, (_, chunk_spec, _, out_selection, _) in zip(
263-
chunk_array_batch, batch_info, strict=False
266+
chunk_array_batch, batch_info_list, strict=False
264267
):
265268
if chunk_array is not None:
266269
if drop_axes:
267270
chunk_array = chunk_array.squeeze(axis=drop_axes)
268271
out[out_selection] = chunk_array
272+
results.append(GetResult(status="present"))
269273
else:
270274
out[out_selection] = fill_value_or_default(chunk_spec)
275+
results.append(GetResult(status="missing"))
271276
else:
277+
batch_info_list = list(batch_info)
272278
chunk_bytes_batch = await concurrent_map(
273-
[(byte_getter, array_spec.prototype) for byte_getter, array_spec, *_ in batch_info],
279+
[
280+
(byte_getter, array_spec.prototype)
281+
for byte_getter, array_spec, *_ in batch_info_list
282+
],
274283
lambda byte_getter, prototype: byte_getter.get(prototype),
275284
config.get("async.concurrency"),
276285
)
277286
chunk_array_batch = await self.decode_batch(
278287
[
279288
(chunk_bytes, chunk_spec)
280289
for chunk_bytes, (_, chunk_spec, *_) in zip(
281-
chunk_bytes_batch, batch_info, strict=False
290+
chunk_bytes_batch, batch_info_list, strict=False
282291
)
283292
],
284293
)
285294
for chunk_array, (_, chunk_spec, chunk_selection, out_selection, _) in zip(
286-
chunk_array_batch, batch_info, strict=False
295+
chunk_array_batch, batch_info_list, strict=False
287296
):
288297
if chunk_array is not None:
289298
tmp = chunk_array[chunk_selection]
290299
if drop_axes:
291300
tmp = tmp.squeeze(axis=drop_axes)
292301
out[out_selection] = tmp
302+
results.append(GetResult(status="present"))
293303
else:
294304
out[out_selection] = fill_value_or_default(chunk_spec)
305+
results.append(GetResult(status="missing"))
306+
return tuple(results)
295307

296308
def _merge_chunk_array(
297309
self,
@@ -471,15 +483,19 @@ async def read(
471483
batch_info: Iterable[tuple[ByteGetter, ArraySpec, SelectorTuple, SelectorTuple, bool]],
472484
out: NDBuffer,
473485
drop_axes: tuple[int, ...] = (),
474-
) -> None:
475-
await concurrent_map(
486+
) -> tuple[GetResult, ...]:
487+
batch_results = await concurrent_map(
476488
[
477489
(single_batch_info, out, drop_axes)
478490
for single_batch_info in batched(batch_info, self.batch_size)
479491
],
480492
self.read_batch,
481493
config.get("async.concurrency"),
482494
)
495+
results: list[GetResult] = []
496+
for batch in batch_results:
497+
results.extend(batch)
498+
return tuple(results)
483499

484500
async def write(
485501
self,

src/zarr/core/common.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
DimensionNamesLike = Iterable[str | None] | None
5151
DimensionNames = DimensionNamesLike # for backwards compatibility
5252

53+
5354
TName = TypeVar("TName", bound=str)
5455
TConfig = TypeVar("TConfig", bound=Mapping[str, object])
5556

0 commit comments

Comments
 (0)