From 4be358686e5e0ddd281f7df9413629f3d5f9cf67 Mon Sep 17 00:00:00 2001 From: spencerkclark Date: Sun, 17 Apr 2022 14:58:53 -0400 Subject: [PATCH 1/4] Add fix to decode_cf_variable --- doc/whats-new.rst | 4 ++++ xarray/conventions.py | 7 ++++++- xarray/tests/test_conventions.py | 20 ++++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 85096a45a39..90f8797f8cd 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -83,6 +83,10 @@ Bug fixes - Allow passing both ``other`` and ``drop=True`` arguments to ``xr.DataArray.where`` and ``xr.Dataset.where`` (:pull:`6466`, :pull:`6467`). By `Michael Delgado `_. +- Ensure dtype encoding attributes are not added or modified on variables that + contain datetime-like values prior to being passed to + :py:func:`xarray.conventions.decode_cf_variable` (:issue:`6453`, :pull:``). + By `Spencer Clark `_. Documentation ~~~~~~~~~~~~~ diff --git a/xarray/conventions.py b/xarray/conventions.py index ebe95b62721..102ef003186 100644 --- a/xarray/conventions.py +++ b/xarray/conventions.py @@ -7,7 +7,7 @@ from .coding import strings, times, variables from .coding.variables import SerializationWarning, pop_to from .core import duck_array_ops, indexing -from .core.common import contains_cftime_datetimes +from .core.common import _contains_datetime_like_objects, contains_cftime_datetimes from .core.pycompat import is_duck_dask_array from .core.variable import IndexVariable, Variable, as_variable @@ -340,6 +340,11 @@ def decode_cf_variable( A variable holding the decoded equivalent of var. """ var = as_variable(var) + + # Ensure datetime-like Variables are passed through unmodified (GH 6453) + if _contains_datetime_like_objects(var): + return var + original_dtype = var.dtype if decode_timedelta is None: diff --git a/xarray/tests/test_conventions.py b/xarray/tests/test_conventions.py index d5d8e00d45f..2635331c042 100644 --- a/xarray/tests/test_conventions.py +++ b/xarray/tests/test_conventions.py @@ -9,6 +9,7 @@ Dataset, SerializationWarning, Variable, + cftime_range, coding, conventions, open_dataset, @@ -442,3 +443,22 @@ def test_decode_cf_variable_with_array_units(self) -> None: v = Variable(["t"], [1, 2, 3], {"units": np.array(["foobar"], dtype=object)}) v_decoded = conventions.decode_cf_variable("test2", v) assert_identical(v, v_decoded) + + +def test_decode_cf_variable_timedelta64(): + variable = Variable(["time"], pd.timedelta_range("1D", periods=2)) + decoded = conventions.decode_cf_variable("time", variable) + assert decoded.encoding == {} + + +def test_decode_cf_variable_datetime64(): + variable = Variable(["time"], pd.date_range("2000", periods=2)) + decoded = conventions.decode_cf_variable("time", variable) + assert decoded.encoding == {} + + +@requires_cftime +def test_decode_cf_variable_cftime(): + variable = Variable(["time"], cftime_range("2000", periods=2)) + decoded = conventions.decode_cf_variable("time", variable) + assert decoded.encoding == {} From 9ba40856acf6224e97f24f394287b93a471bc115 Mon Sep 17 00:00:00 2001 From: spencerkclark Date: Sun, 17 Apr 2022 16:46:33 -0400 Subject: [PATCH 2/4] Add PR link to what's new --- doc/whats-new.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 90f8797f8cd..4d313e94a4b 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -85,8 +85,8 @@ Bug fixes By `Michael Delgado `_. - Ensure dtype encoding attributes are not added or modified on variables that contain datetime-like values prior to being passed to - :py:func:`xarray.conventions.decode_cf_variable` (:issue:`6453`, :pull:``). - By `Spencer Clark `_. + :py:func:`xarray.conventions.decode_cf_variable` (:issue:`6453`, + :pull:`6489`). By `Spencer Clark `_. Documentation ~~~~~~~~~~~~~ From e8706e2348e0ecfb3ebcbdb658fef8ee9e56ed61 Mon Sep 17 00:00:00 2001 From: spencerkclark Date: Sun, 17 Apr 2022 17:22:44 -0400 Subject: [PATCH 3/4] Variable.data is not lazy so only attempt it on object type arrays --- xarray/core/common.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xarray/core/common.py b/xarray/core/common.py index 817b63161bc..3db9b1cfa0c 100644 --- a/xarray/core/common.py +++ b/xarray/core/common.py @@ -1862,7 +1862,10 @@ def _contains_cftime_datetimes(array) -> bool: def contains_cftime_datetimes(var) -> bool: """Check if an xarray.Variable contains cftime.datetime objects""" - return _contains_cftime_datetimes(var.data) + if var.dtype == np.dtype("O") and var.size > 0: + return _contains_cftime_datetimes(var.data) + else: + return False def _contains_datetime_like_objects(var) -> bool: From 31e47e168853c5a571607c83816cdb2d7c3d3a54 Mon Sep 17 00:00:00 2001 From: spencerkclark Date: Sun, 17 Apr 2022 19:40:20 -0400 Subject: [PATCH 4/4] Add a check that the decoded variable is identical to the input --- xarray/tests/test_conventions.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xarray/tests/test_conventions.py b/xarray/tests/test_conventions.py index 2635331c042..b8b9d19e238 100644 --- a/xarray/tests/test_conventions.py +++ b/xarray/tests/test_conventions.py @@ -449,12 +449,14 @@ def test_decode_cf_variable_timedelta64(): variable = Variable(["time"], pd.timedelta_range("1D", periods=2)) decoded = conventions.decode_cf_variable("time", variable) assert decoded.encoding == {} + assert_identical(decoded, variable) def test_decode_cf_variable_datetime64(): variable = Variable(["time"], pd.date_range("2000", periods=2)) decoded = conventions.decode_cf_variable("time", variable) assert decoded.encoding == {} + assert_identical(decoded, variable) @requires_cftime @@ -462,3 +464,4 @@ def test_decode_cf_variable_cftime(): variable = Variable(["time"], cftime_range("2000", periods=2)) decoded = conventions.decode_cf_variable("time", variable) assert decoded.encoding == {} + assert_identical(decoded, variable)