Skip to content

Commit 5cc034d

Browse files
author
Cipher
committed
fix: BaseFloat._check_scalar rejects invalid string values (#3586)
BaseFloat._check_scalar returned True for all strings because the FloatLike type union includes str. This allowed invalid strings like 'not valid' to pass the check and then raise a confusing ValueError in _cast_scalar_unchecked instead of the expected TypeError. Fix _check_scalar to validate string inputs by attempting conversion: - Valid float strings (e.g. 'NaN', 'inf', '-inf', '1.5') return True - Invalid strings (e.g. 'not valid') return False, causing cast_scalar to raise TypeError as expected Add test cases for invalid string inputs to invalid_scalar_params. Fixes #3586
1 parent 1cb1cce commit 5cc034d

2 files changed

Lines changed: 12 additions & 3 deletions

File tree

src/zarr/core/dtype/npy/float.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,15 @@ def _check_scalar(self, data: object) -> TypeGuard[FloatLike]:
201201
TypeGuard[FloatLike]
202202
True if the input is a valid scalar value, False otherwise.
203203
"""
204+
if isinstance(data, str):
205+
# Only accept strings that are valid float representations (e.g. "NaN", "inf").
206+
# Plain strings that cannot be converted should return False so that cast_scalar
207+
# raises TypeError rather than a confusing ValueError.
208+
try:
209+
self.to_native_dtype().type(data)
210+
return True
211+
except (ValueError, OverflowError):
212+
return False
204213
return isinstance(data, FloatLike)
205214

206215
def _cast_scalar_unchecked(self, data: FloatLike) -> TFloatScalar_co:

tests/test_dtype/test_npy/test_float.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class TestFloat16(_BaseTestFloat):
6565
(Float16(), -1.0, np.float16(-1.0)),
6666
(Float16(), "NaN", np.float16("NaN")),
6767
)
68-
invalid_scalar_params = ((Float16(), {"set!"}),)
68+
invalid_scalar_params = ((Float16(), {"set!"}), (Float16(), "not_a_float"),)
6969
hex_string_params = (("0x7fc0", np.nan), ("0x7fc1", np.nan), ("0x3c00", 1.0))
7070
item_size_params = (Float16(),)
7171

@@ -113,7 +113,7 @@ class TestFloat32(_BaseTestFloat):
113113
(Float32(), -1.0, np.float32(-1.0)),
114114
(Float32(), "NaN", np.float32("NaN")),
115115
)
116-
invalid_scalar_params = ((Float32(), {"set!"}),)
116+
invalid_scalar_params = ((Float32(), {"set!"}), (Float32(), "not_a_float"),)
117117
hex_string_params = (("0x7fc00000", np.nan), ("0x7fc00001", np.nan), ("0x3f800000", 1.0))
118118
item_size_params = (Float32(),)
119119

@@ -160,7 +160,7 @@ class TestFloat64(_BaseTestFloat):
160160
(Float64(), -1.0, np.float64(-1.0)),
161161
(Float64(), "NaN", np.float64("NaN")),
162162
)
163-
invalid_scalar_params = ((Float64(), {"set!"}),)
163+
invalid_scalar_params = ((Float64(), {"set!"}), (Float64(), "not_a_float"),)
164164
hex_string_params = (
165165
("0x7ff8000000000000", np.nan),
166166
("0x7ff8000000000001", np.nan),

0 commit comments

Comments
 (0)