Skip to content

Commit 0e67a04

Browse files
committed
Tweak errors and warnings; relax decoding dtype error
1 parent ea9b443 commit 0e67a04

File tree

2 files changed

+58
-25
lines changed

2 files changed

+58
-25
lines changed

xarray/coding/times.py

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

33
import re
4-
import typing
54
import warnings
65
from collections.abc import Callable, Hashable
76
from datetime import datetime, timedelta
@@ -1464,13 +1463,16 @@ def encode(self, variable: Variable, name: T_Name = None) -> Variable:
14641463
):
14651464
raise ValueError(
14661465
f"Specifying 'add_offset' or 'scale_factor' is not "
1467-
f"supported when literally encoding the "
1468-
f"np.timedelta64 values of variable {name!r}. To "
1469-
f"encode {name!r} with such encoding parameters, "
1470-
f"additionally set encoding['units'] to a unit of "
1471-
f"time, e.g. 'seconds'. To proceed with literal "
1472-
f"np.timedelta64 encoding of {name!r}, remove any "
1473-
f"encoding entries for 'add_offset' or 'scale_factor'."
1466+
f"supported when encoding the timedelta64 values of "
1467+
f"variable {name!r} with xarray's new default "
1468+
f"timedelta64 encoding approach. To encode {name!r} "
1469+
f"with xarray's previous timedelta64 encoding "
1470+
f"approach, which supports the 'add_offset' and "
1471+
f"'scale_factor' parameters, additionally set "
1472+
f"encoding['units'] to a unit of time, e.g. "
1473+
f"'seconds'. To proceed with encoding of {name!r} "
1474+
f"via xarray's new approach, remove any encoding "
1475+
f"entries for 'add_offset' or 'scale_factor'."
14741476
)
14751477
if "_FillValue" not in encoding and "missing_value" not in encoding:
14761478
encoding["_FillValue"] = np.iinfo(np.int64).min
@@ -1497,33 +1499,59 @@ def decode(self, variable: Variable, name: T_Name = None) -> Variable:
14971499
k in encoding for k in _INVALID_LITERAL_TIMEDELTA64_ENCODING_KEYS
14981500
):
14991501
raise ValueError(
1500-
"Decoding np.timedelta64 values via dtype is not "
1501-
"supported when 'add_offset', or 'scale_factor' are "
1502-
"present in encoding."
1502+
f"Decoding timedelta64 values via dtype is not "
1503+
f"supported when 'add_offset', or 'scale_factor' are "
1504+
f"present in encoding. Check the encoding parameters "
1505+
f"of variable {name!r}."
15031506
)
15041507
dtype = pop_to(attrs, encoding, "dtype", name=name)
15051508
dtype = np.dtype(dtype)
15061509
resolution, _ = np.datetime_data(dtype)
1507-
if resolution not in typing.get_args(PDDatetimeUnitOptions):
1508-
raise ValueError(
1510+
if np.timedelta64(1, resolution) > np.timedelta64(1, "s"):
1511+
time_unit = cast(PDDatetimeUnitOptions, "s")
1512+
dtype = np.dtype("timedelta64[s]")
1513+
message = (
15091514
f"Following pandas, xarray only supports decoding to "
15101515
f"timedelta64 values with a resolution of 's', 'ms', "
1511-
f"'us', or 'ns'. Encoded values have a resolution of "
1512-
f"{resolution!r}."
1516+
f"'us', or 'ns'. Encoded values for variable {name!r} "
1517+
f"have a resolution of {resolution!r}. Attempting to "
1518+
f"decode to a resolution of 's'. Note, depending on "
1519+
f"the encoded values, this may lead to an "
1520+
f"OverflowError. Additionally, data will not be "
1521+
f"identically round tripped; xarray will choose an "
1522+
f"encoding dtype of 'timedelta64[s]' when re-encoding."
15131523
)
1514-
time_unit = cast(PDDatetimeUnitOptions, resolution)
1524+
emit_user_level_warning(message)
1525+
elif np.timedelta64(1, resolution) < np.timedelta64(1, "ns"):
1526+
time_unit = cast(PDDatetimeUnitOptions, "ns")
1527+
dtype = np.dtype("timedelta64[ns]")
1528+
message = (
1529+
f"Following pandas, xarray only supports decoding to "
1530+
f"timedelta64 values with a resolution of 's', 'ms', "
1531+
f"'us', or 'ns'. Encoded values for variable {name!r} "
1532+
f"have a resolution of {resolution!r}. Attempting to "
1533+
f"decode to a resolution of 'ns'. Note, depending on "
1534+
f"the encoded values, this may lead to loss of "
1535+
f"precision. Additionally, data will not be "
1536+
f"identically round tripped; xarray will choose an "
1537+
f"encoding dtype of 'timedelta64[ns]' "
1538+
f"when re-encoding."
1539+
)
1540+
emit_user_level_warning(message)
1541+
else:
1542+
time_unit = cast(PDDatetimeUnitOptions, resolution)
15151543
elif self.decode_via_units:
15161544
if self._emit_decode_timedelta_future_warning:
15171545
emit_user_level_warning(
15181546
"In a future version, xarray will not decode "
15191547
"timedelta values based on the presence of a "
15201548
"timedelta-like units attribute by default. Instead "
1521-
"it will rely on the presence of a np.timedelta64 "
1522-
"dtype attribute, which is now xarray's default way "
1523-
"of encoding np.timedelta64 values. To continue "
1524-
"decoding timedeltas based on the presence of a "
1525-
"timedelta-like units attribute, users will need to "
1526-
"explicitly opt-in by passing True or "
1549+
"it will rely on the presence of a timedelta64 dtype "
1550+
"attribute, which is now xarray's default way of "
1551+
"encoding timedelta64 values. To continue decoding "
1552+
"timedeltas based on the presence of a timedelta-like "
1553+
"units attribute, users will need to explicitly "
1554+
"opt-in by passing True or "
15271555
"CFTimedeltaCoder(decode_via_units=True) to "
15281556
"decode_timedelta. To silence this warning, set "
15291557
"decode_timedelta to True, False, or a "

xarray/tests/test_coding_times.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1986,11 +1986,16 @@ def test_literal_timedelta64_coding(time_unit: PDDatetimeUnitOptions) -> None:
19861986
assert reencoded.dtype == encoded.dtype
19871987

19881988

1989-
def test_literal_timedelta_coding_resolution_error() -> None:
1989+
def test_literal_timedelta_coding_non_pandas_resolution_warning() -> None:
19901990
attrs = {"dtype": "timedelta64[D]", "units": "days"}
19911991
encoded = Variable(["time"], [0, 1, 2], attrs=attrs)
1992-
with pytest.raises(ValueError, match="xarray only supports"):
1993-
conventions.decode_cf_variable("timedeltas", encoded)
1992+
with pytest.warns(UserWarning, match="xarray only supports"):
1993+
decoded = conventions.decode_cf_variable("timedeltas", encoded)
1994+
expected_array = np.array([0, 1, 2], dtype="timedelta64[D]")
1995+
expected_array = expected_array.astype("timedelta64[s]")
1996+
expected = Variable(["time"], expected_array)
1997+
assert_identical(decoded, expected)
1998+
assert decoded.dtype == np.dtype("timedelta64[s]")
19941999

19952000

19962001
@pytest.mark.parametrize("attribute", ["dtype", "units"])

0 commit comments

Comments
 (0)