3939from zarr_metadata .v3 ._definition import as_kind , kind_of , no_pipelines , storage_of , unchanged
4040from zarr_metadata .v3 ._pipeline import read_pipeline
4141from zarr_metadata .v3 .chunk_grid .rectilinear import RECTILINEAR_CHUNK_GRID
42- from zarr_metadata .v3 .codec ._arithmetic import COMPLEX , NOT_NUMBERS
4342from zarr_metadata .v3 .codec .bytes import BYTES_CODEC
4443from zarr_metadata .v3 .codec .cast_value import CAST_VALUE_CODEC
4544from zarr_metadata .v3 .codec .gzip import GZIP_CODEC
@@ -276,7 +275,28 @@ def test_a_cast_from_a_data_type_without_a_strategy_draws_numbers() -> None:
276275 find (configurations , lambda configuration : "scalar_map" in configuration , settings = _REACH )
277276
278277
279- @given (data = st .data (), chunk = _chunks ())
278+ @st .composite
279+ def _partly_known_chunks (draw : st .DrawFn ) -> Chunk :
280+ """A chunk some of which nothing says: its lengths along an axis or at all, or its data type, read by nothing in scope."""
281+ chunk = draw (_chunks ())
282+ lengths = draw (
283+ st .sampled_from (
284+ [
285+ chunk .lengths ,
286+ None ,
287+ None if chunk .lengths is None else tuple (None for _ in chunk .lengths ),
288+ ]
289+ )
290+ )
291+ data_type = draw (st .sampled_from ([chunk .data_type , None , _UNREAD_DATA_TYPE ]))
292+ return Chunk (lengths , data_type )
293+
294+
295+ _UNREAD_DATA_TYPE = resolve ({"name" : "an.unread.type" }, DataTypeDefinition , CORE_AND_EXTENSIONS )[0 ]
296+ """A data type field that nothing in scope claims: a chunk of it says nothing of its values."""
297+
298+
299+ @given (data = st .data (), chunk = _chunks () | _partly_known_chunks ())
280300def test_pipelines_read (data : st .DataObject , chunk : Chunk ) -> None :
281301 """A pipeline drawn for a chunk reads as one handed it, through JSON too; none is drawn only for a chunk no codec encodes."""
282302 drawn = pipelines (chunk )
@@ -419,6 +439,14 @@ def test_a_codec_strategy_refusing_an_unknown_chunk_is_a_value_error() -> None:
419439 fields (GZIP_CODEC , strategies = DEFAULT_STRATEGIES | {GZIP_CODEC : refusing })
420440
421441
442+ def test_fill_values_of_a_field_no_definition_reads_is_a_lookup_error () -> None :
443+ """A struct handed a field type that no definition in the strategies reads has no fill values to draw for it."""
444+ without_float32 = {d : s for d , s in DEFAULT_STRATEGIES .items () if d is not FLOAT32_DATA_TYPE }
445+ configuration : Any = {"fields" : ({"name" : "a" , "data_type" : "float32" },)}
446+ with pytest .raises (LookupError , match = "no definition in `strategies` reads" ):
447+ fill_values (STRUCT_DATA_TYPE , configuration , strategies = without_float32 )
448+
449+
422450def test_a_refused_nested_draw_is_a_value_error () -> None :
423451 """A field a configuration holds is read as it is drawn, so a strategy that draws a refused one is caught there."""
424452 refused = DataTypeStrategy (
@@ -429,7 +457,7 @@ def test_a_refused_nested_draw_is_a_value_error() -> None:
429457 CAST_VALUE_CODEC : DEFAULT_STRATEGIES [CAST_VALUE_CODEC ],
430458 NUMPY_DATETIME64_DATA_TYPE : refused ,
431459 }
432- with pytest .raises (ValueError , match = "which is refused" ):
460+ with pytest .raises (ValueError , match = "read in the strategies. scope, is refused" ):
433461 find (fields (CAST_VALUE_CODEC , strategies = strategies ), lambda _field : True , settings = _ONCE )
434462
435463
@@ -560,16 +588,21 @@ def test_pipelines_reach_every_codec(definition: CodecDefinition[Any]) -> None:
560588 )
561589
562590
563- @pytest .mark .parametrize ("member" , ["codecs" , "index_codecs" ])
564591@pytest .mark .parametrize (
565- "definition" , [d for d in _CODECS if d is not SHARDING_INDEXED_CODEC ], ids = _id
592+ ("definition" , "member" ),
593+ [
594+ (d , member )
595+ for d in _CODECS
596+ if d is not SHARDING_INDEXED_CODEC
597+ for member in ("codecs" , "index_codecs" )
598+ if member == "codecs" or d .size == "static"
599+ ],
600+ ids = _id ,
566601)
567602def test_shards_hold_every_codec_their_pipeline_takes (
568603 definition : CodecDefinition [Any ], member : str
569604) -> None :
570605 """A shard's pipelines reach each codec they take: its index codecs, only those of static size."""
571- if member == "index_codecs" and definition .size != "static" :
572- return
573606 find (
574607 _shards (),
575608 lambda shard : (definition .name , (member ,)) in _codecs_in ((shard ,)),
@@ -612,8 +645,18 @@ def _read_data_type(field: object) -> Any: # noqa: ANN401
612645 return resolved
613646
614647
615- _REAL_NUMBERS = [d for d in _DATA_TYPES if d .name not in NOT_NUMBERS | COMPLEX ]
616- """The data types `cast_value` casts to: those that model real numbers."""
648+ _REAL_NUMBERS = [
649+ d
650+ for d in _DATA_TYPES
651+ if d .name
652+ in {
653+ * (f"{ sign } int{ bits } " for sign in ("" , "u" ) for bits in (8 , 16 , 32 , 64 )),
654+ * (f"float{ bits } " for bits in (16 , 32 , 64 )),
655+ "numpy.datetime64" ,
656+ "numpy.timedelta64" ,
657+ }
658+ ]
659+ """The data types `cast_value` casts to: integers and floats, and the numpy times, which are signed 64-bit integers."""
617660
618661
619662@pytest .mark .parametrize ("definition" , _REAL_NUMBERS , ids = _id )
0 commit comments