43
43
44
44
DEFAULT_DTYPE = "float64"
45
45
46
+ # Keep in sync with _replace_special_floats
47
+ SPECIAL_FLOATS_ENCODED = {
48
+ "Infinity" : np .inf ,
49
+ "-Infinity" : - np .inf ,
50
+ "NaN" : np .nan ,
51
+ }
52
+
46
53
47
54
def parse_zarr_format (data : object ) -> Literal [3 ]:
48
55
if data == 3 :
@@ -149,7 +156,7 @@ def default(self, o: object) -> Any:
149
156
if isinstance (out , complex ):
150
157
# python complex types are not JSON serializable, so we use the
151
158
# serialization defined in the zarr v3 spec
152
- return [out .real , out .imag ]
159
+ return _replace_special_floats ( [out .real , out .imag ])
153
160
elif np .isnan (out ):
154
161
return "NaN"
155
162
elif np .isinf (out ):
@@ -447,8 +454,11 @@ def parse_fill_value(
447
454
if isinstance (fill_value , Sequence ) and not isinstance (fill_value , str ):
448
455
if data_type in (DataType .complex64 , DataType .complex128 ):
449
456
if len (fill_value ) == 2 :
457
+ decoded_fill_value = tuple (
458
+ SPECIAL_FLOATS_ENCODED .get (value , value ) for value in fill_value
459
+ )
450
460
# complex datatypes serialize to JSON arrays with two elements
451
- return np_dtype .type (complex (* fill_value ))
461
+ return np_dtype .type (complex (* decoded_fill_value ))
452
462
else :
453
463
msg = (
454
464
f"Got an invalid fill value for complex data type { data_type .value } ."
@@ -475,12 +485,20 @@ def parse_fill_value(
475
485
pass
476
486
elif fill_value in ["Infinity" , "-Infinity" ] and not np .isfinite (casted_value ):
477
487
pass
478
- elif np_dtype .kind in "cf " :
488
+ elif np_dtype .kind == "f " :
479
489
# float comparison is not exact, especially when dtype <float64
480
- # so we us np.isclose for this comparison.
490
+ # so we use np.isclose for this comparison.
481
491
# this also allows us to compare nan fill_values
482
492
if not np .isclose (fill_value , casted_value , equal_nan = True ):
483
493
raise ValueError (f"fill value { fill_value !r} is not valid for dtype { data_type } " )
494
+ elif np_dtype .kind == "c" :
495
+ # confusingly np.isclose(np.inf, np.inf + 0j) is False on numpy<2, so compare real and imag parts
496
+ # explicitly.
497
+ if not (
498
+ np .isclose (np .real (fill_value ), np .real (casted_value ), equal_nan = True )
499
+ and np .isclose (np .imag (fill_value ), np .imag (casted_value ), equal_nan = True )
500
+ ):
501
+ raise ValueError (f"fill value { fill_value !r} is not valid for dtype { data_type } " )
484
502
else :
485
503
if fill_value != casted_value :
486
504
raise ValueError (f"fill value { fill_value !r} is not valid for dtype { data_type } " )
0 commit comments