@@ -1964,14 +1964,15 @@ def test_decode_floating_point_timedelta_no_serialization_warning() -> None:
1964
1964
1965
1965
1966
1966
def test_literal_timedelta64_coding (time_unit : PDDatetimeUnitOptions ) -> None :
1967
- timedeltas = pd . timedelta_range ( 0 , freq = "D" , periods = 3 , unit = time_unit ) # type: ignore[call-arg]
1967
+ timedeltas = np . array ([ 0 , 1 , "NaT" ], dtype = f"timedelta64[ { time_unit } ]" )
1968
1968
variable = Variable (["time" ], timedeltas )
1969
1969
expected_dtype = f"timedelta64[{ time_unit } ]"
1970
1970
expected_units = _numpy_to_netcdf_timeunit (time_unit )
1971
1971
1972
1972
encoded = conventions .encode_cf_variable (variable )
1973
1973
assert encoded .attrs ["dtype" ] == expected_dtype
1974
1974
assert encoded .attrs ["units" ] == expected_units
1975
+ assert encoded .attrs ["_FillValue" ] == np .iinfo (np .int64 ).min
1975
1976
1976
1977
decoded = conventions .decode_cf_variable ("timedeltas" , encoded )
1977
1978
assert decoded .encoding ["dtype" ] == expected_dtype
@@ -2011,7 +2012,7 @@ def test_literal_timedelta_encode_invalid_attribute(attribute) -> None:
2011
2012
2012
2013
2013
2014
@pytest .mark .parametrize ("invalid_key" , _INVALID_LITERAL_TIMEDELTA64_ENCODING_KEYS )
2014
- def test_literal_timedelta_encoding_mask_and_scale_error (invalid_key ) -> None :
2015
+ def test_literal_timedelta_encoding_invalid_key_error (invalid_key ) -> None :
2015
2016
encoding = {invalid_key : 1.0 }
2016
2017
timedeltas = pd .timedelta_range (0 , freq = "D" , periods = 3 )
2017
2018
variable = Variable (["time" ], timedeltas , encoding = encoding )
@@ -2020,7 +2021,7 @@ def test_literal_timedelta_encoding_mask_and_scale_error(invalid_key) -> None:
2020
2021
2021
2022
2022
2023
@pytest .mark .parametrize ("invalid_key" , _INVALID_LITERAL_TIMEDELTA64_ENCODING_KEYS )
2023
- def test_literal_timedelta_decoding_mask_and_scale_error (invalid_key ) -> None :
2024
+ def test_literal_timedelta_decoding_invalid_key_error (invalid_key ) -> None :
2024
2025
attrs = {invalid_key : 1.0 , "dtype" : "timedelta64[s]" , "units" : "seconds" }
2025
2026
variable = Variable (["time" ], [0 , 1 , 2 ], attrs = attrs )
2026
2027
with pytest .raises (ValueError , match = invalid_key ):
@@ -2044,6 +2045,12 @@ def test_literal_timedelta_decoding_mask_and_scale_error(invalid_key) -> None:
2044
2045
def test_timedelta_decoding_options (
2045
2046
decode_via_units , decode_via_dtype , attrs , expect_timedelta64
2046
2047
) -> None :
2048
+ # Note with literal timedelta encoding, we always add a _FillValue, even
2049
+ # if one is not present in the original encoding parameters, which is why
2050
+ # we ensure one is defined here when "dtype" is present in attrs.
2051
+ if "dtype" in attrs :
2052
+ attrs ["_FillValue" ] = np .iinfo (np .int64 ).min
2053
+
2047
2054
array = np .array ([0 , 1 , 2 ], dtype = np .dtype ("int64" ))
2048
2055
encoded = Variable (["time" ], array , attrs = attrs )
2049
2056
@@ -2083,3 +2090,33 @@ def test_timedelta_encoding_explicit_non_timedelta64_dtype() -> None:
2083
2090
assert_identical (reencoded , encoded )
2084
2091
assert encoded .attrs ["units" ] == "days"
2085
2092
assert encoded .dtype == np .dtype ("int32" )
2093
+
2094
+
2095
+ @pytest .mark .parametrize ("mask_attribute" , ["_FillValue" , "missing_value" ])
2096
+ def test_literal_timedelta64_coding_with_mask (
2097
+ time_unit : PDDatetimeUnitOptions , mask_attribute : str
2098
+ ) -> None :
2099
+ timedeltas = np .array ([0 , 1 , "NaT" ], dtype = f"timedelta64[{ time_unit } ]" )
2100
+ mask = 10
2101
+ variable = Variable (["time" ], timedeltas , encoding = {mask_attribute : mask })
2102
+ expected_dtype = f"timedelta64[{ time_unit } ]"
2103
+ expected_units = _numpy_to_netcdf_timeunit (time_unit )
2104
+
2105
+ encoded = conventions .encode_cf_variable (variable )
2106
+ assert encoded .attrs ["dtype" ] == expected_dtype
2107
+ assert encoded .attrs ["units" ] == expected_units
2108
+ assert encoded .attrs [mask_attribute ] == mask
2109
+ assert encoded [- 1 ] == mask
2110
+
2111
+ decoded = conventions .decode_cf_variable ("timedeltas" , encoded )
2112
+ assert decoded .encoding ["dtype" ] == expected_dtype
2113
+ assert decoded .encoding ["units" ] == expected_units
2114
+ assert decoded .encoding [mask_attribute ] == mask
2115
+ assert np .isnat (decoded [- 1 ])
2116
+
2117
+ assert_identical (decoded , variable )
2118
+ assert decoded .dtype == variable .dtype
2119
+
2120
+ reencoded = conventions .encode_cf_variable (decoded )
2121
+ assert_identical (reencoded , encoded )
2122
+ assert reencoded .dtype == encoded .dtype
0 commit comments