From 44d310ba858090ecea794a834369a191a1add9b9 Mon Sep 17 00:00:00 2001 From: Joseph Hamman Date: Thu, 19 Sep 2024 19:27:27 -0700 Subject: [PATCH] check that fill value is valid for dtype --- src/zarr/core/metadata/v3.py | 12 +++++++++++- tests/v3/test_metadata/test_v3.py | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/zarr/core/metadata/v3.py b/src/zarr/core/metadata/v3.py index 6d7253196..34a33103c 100644 --- a/src/zarr/core/metadata/v3.py +++ b/src/zarr/core/metadata/v3.py @@ -332,7 +332,17 @@ def parse_fill_value( raise ValueError(msg) msg = f"Cannot parse non-string sequence {fill_value} as a scalar with type {dtype}." raise TypeError(msg) - return dtype.type(fill_value) # type: ignore[arg-type] + + # Cast the fill_value to the given dtype + try: + casted_value = np.dtype(dtype).type(fill_value) + except (ValueError, OverflowError, TypeError) as e: + raise ValueError(f"fill value {fill_value!r} is not valid for dtype {dtype}") from e + # Check if the value is still representable by the dtype + if fill_value != casted_value: + raise ValueError(f"fill value {fill_value!r} is not valid for dtype {dtype}") + + return casted_value # For type checking diff --git a/tests/v3/test_metadata/test_v3.py b/tests/v3/test_metadata/test_v3.py index a8f61f90e..7bfa2e019 100644 --- a/tests/v3/test_metadata/test_v3.py +++ b/tests/v3/test_metadata/test_v3.py @@ -277,3 +277,21 @@ async def test_invalid_dtype_raises() -> None: def test_parse_invalid_dtype_raises(data): with pytest.raises(ValueError, match=r"Invalid V3 data_type"): parse_dtype(data) + + +@pytest.mark.parametrize( + "data_type,fill_value", [("uint8", -1), ("int32", 22.5), ("float32", "foo")] +) +async def test_invalid_fill_value_raises(data_type: str, fill_value: int | float) -> None: + metadata_dict = { + "zarr_format": 3, + "node_type": "array", + "shape": (1,), + "chunk_grid": {"name": "regular", "configuration": {"chunk_shape": (1,)}}, + "data_type": data_type, + "chunk_key_encoding": {"name": "default", "separator": "."}, + "codecs": (), + "fill_value": fill_value, # this is not a valid fill value for uint8 + } + with pytest.raises(ValueError, match=rf"fill value .* is not valid for dtype {data_type}"): + ArrayV3Metadata.from_dict(metadata_dict)