@@ -220,6 +220,20 @@ def compute_encoded_size(self, byte_length: int, array_spec: ArraySpec) -> int:
220220 return byte_length
221221
222222
223+ @dataclass (slots = True )
224+ class ChunkRequest :
225+ """A single chunk's worth of metadata for a pipeline read or write.
226+
227+ Replaces the anonymous 5-tuples formerly threaded through ``batch_info``.
228+ """
229+
230+ byte_setter : ByteSetter
231+ chunk_spec : ArraySpec
232+ chunk_selection : SelectorTuple
233+ out_selection : SelectorTuple
234+ is_complete_chunk : bool
235+
236+
223237@dataclass (frozen = True )
224238class BatchedCodecPipeline (CodecPipeline ):
225239 """Default codec pipeline.
@@ -400,48 +414,40 @@ async def encode_partial_batch(
400414
401415 async def read_batch (
402416 self ,
403- batch_info : Iterable [tuple [ ByteGetter , ArraySpec , SelectorTuple , SelectorTuple , bool ] ],
417+ batch_info : Iterable [ChunkRequest ],
404418 out : NDBuffer ,
405419 drop_axes : tuple [int , ...] = (),
406420 ) -> None :
421+ batch_info = list (batch_info )
407422 if self .supports_partial_decode :
408423 chunk_array_batch = await self .decode_partial_batch (
409- [
410- (byte_getter , chunk_selection , chunk_spec )
411- for byte_getter , chunk_spec , chunk_selection , * _ in batch_info
412- ]
424+ [(req .byte_setter , req .chunk_selection , req .chunk_spec ) for req in batch_info ]
413425 )
414- for chunk_array , (_ , chunk_spec , _ , out_selection , _ ) in zip (
415- chunk_array_batch , batch_info , strict = False
416- ):
426+ for chunk_array , req in zip (chunk_array_batch , batch_info , strict = False ):
417427 if chunk_array is not None :
418- out [out_selection ] = chunk_array
428+ out [req . out_selection ] = chunk_array
419429 else :
420- out [out_selection ] = fill_value_or_default (chunk_spec )
430+ out [req . out_selection ] = fill_value_or_default (req . chunk_spec )
421431 else :
422432 chunk_bytes_batch = await concurrent_map (
423- [(byte_getter , chunk_spec .prototype ) for byte_getter , chunk_spec , * _ in batch_info ],
433+ [(req . byte_setter , req . chunk_spec .prototype ) for req in batch_info ],
424434 lambda byte_getter , prototype : byte_getter .get (prototype ),
425435 config .get ("async.concurrency" ),
426436 )
427437 chunk_array_batch = await self .decode_batch (
428438 [
429- (chunk_bytes , chunk_spec )
430- for chunk_bytes , (_ , chunk_spec , * _ ) in zip (
431- chunk_bytes_batch , batch_info , strict = False
432- )
439+ (chunk_bytes , req .chunk_spec )
440+ for chunk_bytes , req in zip (chunk_bytes_batch , batch_info , strict = False )
433441 ],
434442 )
435- for chunk_array , (_ , chunk_spec , chunk_selection , out_selection , _ ) in zip (
436- chunk_array_batch , batch_info , strict = False
437- ):
443+ for chunk_array , req in zip (chunk_array_batch , batch_info , strict = False ):
438444 if chunk_array is not None :
439- tmp = chunk_array [chunk_selection ]
445+ tmp = chunk_array [req . chunk_selection ]
440446 if drop_axes != ():
441447 tmp = tmp .squeeze (axis = drop_axes )
442- out [out_selection ] = tmp
448+ out [req . out_selection ] = tmp
443449 else :
444- out [out_selection ] = fill_value_or_default (chunk_spec )
450+ out [req . out_selection ] = fill_value_or_default (req . chunk_spec )
445451
446452 def _merge_chunk_array (
447453 self ,
@@ -450,13 +456,11 @@ def _merge_chunk_array(
450456 out_selection : SelectorTuple ,
451457 chunk_spec : ArraySpec ,
452458 chunk_selection : SelectorTuple ,
453- is_complete_chunk : bool ,
454459 drop_axes : tuple [int , ...],
455460 ) -> NDBuffer :
456461 if (
457- is_complete_chunk
462+ existing_chunk_array is None
458463 and value .shape == chunk_spec .shape
459- # Guard that this is not a partial chunk at the end with is_complete_chunk=True
460464 and value [out_selection ].shape == chunk_spec .shape
461465 ):
462466 return value
@@ -489,24 +493,30 @@ def _merge_chunk_array(
489493
490494 async def write_batch (
491495 self ,
492- batch_info : Iterable [tuple [ ByteSetter , ArraySpec , SelectorTuple , SelectorTuple , bool ] ],
496+ batch_info : Iterable [ChunkRequest ],
493497 value : NDBuffer ,
494498 drop_axes : tuple [int , ...] = (),
495499 ) -> None :
500+ batch_info = list (batch_info )
496501 if self .supports_partial_encode :
497502 # Pass scalar values as is
498503 if len (value .shape ) == 0 :
499504 await self .encode_partial_batch (
500505 [
501- (byte_setter , value , chunk_selection , chunk_spec )
502- for byte_setter , chunk_spec , chunk_selection , out_selection , _ in batch_info
506+ (req . byte_setter , value , req . chunk_selection , req . chunk_spec )
507+ for req in batch_info
503508 ],
504509 )
505510 else :
506511 await self .encode_partial_batch (
507512 [
508- (byte_setter , value [out_selection ], chunk_selection , chunk_spec )
509- for byte_setter , chunk_spec , chunk_selection , out_selection , _ in batch_info
513+ (
514+ req .byte_setter ,
515+ value [req .out_selection ],
516+ req .chunk_selection ,
517+ req .chunk_spec ,
518+ )
519+ for req in batch_info
510520 ],
511521 )
512522
@@ -523,61 +533,48 @@ async def _read_key(
523533 chunk_bytes_batch = await concurrent_map (
524534 [
525535 (
526- None if is_complete_chunk else byte_setter ,
527- chunk_spec .prototype ,
536+ None if req . is_complete_chunk else req . byte_setter ,
537+ req . chunk_spec .prototype ,
528538 )
529- for byte_setter , chunk_spec , chunk_selection , _ , is_complete_chunk in batch_info
539+ for req in batch_info
530540 ],
531541 _read_key ,
532542 config .get ("async.concurrency" ),
533543 )
534544 chunk_array_decoded = await self .decode_batch (
535545 [
536- (chunk_bytes , chunk_spec )
537- for chunk_bytes , (_ , chunk_spec , * _ ) in zip (
538- chunk_bytes_batch , batch_info , strict = False
539- )
546+ (chunk_bytes , req .chunk_spec )
547+ for chunk_bytes , req in zip (chunk_bytes_batch , batch_info , strict = False )
540548 ],
541549 )
542550
543551 chunk_array_merged = [
544552 self ._merge_chunk_array (
545553 chunk_array ,
546554 value ,
547- out_selection ,
548- chunk_spec ,
549- chunk_selection ,
550- is_complete_chunk ,
555+ req .out_selection ,
556+ req .chunk_spec ,
557+ req .chunk_selection ,
551558 drop_axes ,
552559 )
553- for chunk_array , (
554- _ ,
555- chunk_spec ,
556- chunk_selection ,
557- out_selection ,
558- is_complete_chunk ,
559- ) in zip (chunk_array_decoded , batch_info , strict = False )
560+ for chunk_array , req in zip (chunk_array_decoded , batch_info , strict = False )
560561 ]
561562 chunk_array_batch : list [NDBuffer | None ] = []
562- for chunk_array , (_ , chunk_spec , * _ ) in zip (
563- chunk_array_merged , batch_info , strict = False
564- ):
563+ for chunk_array , req in zip (chunk_array_merged , batch_info , strict = False ):
565564 if chunk_array is None :
566565 chunk_array_batch .append (None ) # type: ignore[unreachable]
567566 else :
568- if not chunk_spec .config .write_empty_chunks and chunk_array .all_equal (
569- fill_value_or_default (chunk_spec )
567+ if not req . chunk_spec .config .write_empty_chunks and chunk_array .all_equal (
568+ fill_value_or_default (req . chunk_spec )
570569 ):
571570 chunk_array_batch .append (None )
572571 else :
573572 chunk_array_batch .append (chunk_array )
574573
575574 chunk_bytes_batch = await self .encode_batch (
576575 [
577- (chunk_array , chunk_spec )
578- for chunk_array , (_ , chunk_spec , * _ ) in zip (
579- chunk_array_batch , batch_info , strict = False
580- )
576+ (chunk_array , req .chunk_spec )
577+ for chunk_array , req in zip (chunk_array_batch , batch_info , strict = False )
581578 ],
582579 )
583580
@@ -589,10 +586,8 @@ async def _write_key(byte_setter: ByteSetter, chunk_bytes: Buffer | None) -> Non
589586
590587 await concurrent_map (
591588 [
592- (byte_setter , chunk_bytes )
593- for chunk_bytes , (byte_setter , * _ ) in zip (
594- chunk_bytes_batch , batch_info , strict = False
595- )
589+ (req .byte_setter , chunk_bytes )
590+ for chunk_bytes , req in zip (chunk_bytes_batch , batch_info , strict = False )
596591 ],
597592 _write_key ,
598593 config .get ("async.concurrency" ),
@@ -618,7 +613,7 @@ async def encode(
618613
619614 async def read (
620615 self ,
621- batch_info : Iterable [tuple [ ByteGetter , ArraySpec , SelectorTuple , SelectorTuple , bool ] ],
616+ batch_info : Iterable [ChunkRequest ],
622617 out : NDBuffer ,
623618 drop_axes : tuple [int , ...] = (),
624619 ) -> None :
@@ -633,7 +628,7 @@ async def read(
633628
634629 async def write (
635630 self ,
636- batch_info : Iterable [tuple [ ByteSetter , ArraySpec , SelectorTuple , SelectorTuple , bool ] ],
631+ batch_info : Iterable [ChunkRequest ],
637632 value : NDBuffer ,
638633 drop_axes : tuple [int , ...] = (),
639634 ) -> None :
0 commit comments