Skip to content

Commit 2c43663

Browse files
ghislainppre-commit-ci[bot]andersy005TomNicholas
authored
Fix bug with netcdf when units attribute is not a string (#7085)
* solve a bug when the units attribute is not a string (it happens that it is np.nan) * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * update the bug fixes section Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Anderson Banihirwe <[email protected]> Co-authored-by: Tom Nicholas <[email protected]>
1 parent 5ba830d commit 2c43663

File tree

5 files changed

+22
-2
lines changed

5 files changed

+22
-2
lines changed

doc/whats-new.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ Deprecations
4242
Bug fixes
4343
~~~~~~~~~
4444

45+
- Allow reading netcdf files where the 'units' attribute is a number(:pull:`7085`)
46+
By `Ghislain Picard <https://github.com/ghislainp>`_.
4547
- Allow decoding of 0 sized datetimes(:issue:`1329`, :pull:`6882`)
4648
By `Deepak Cherian <https://github.com/dcherian>`_.
4749
- Make sure DataArray.name is always a string when used as label for plotting.

xarray/coding/times.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,8 @@ def encode(self, variable, name=None):
681681
def decode(self, variable, name=None):
682682
dims, data, attrs, encoding = unpack_for_decoding(variable)
683683

684-
if "units" in attrs and "since" in attrs["units"]:
684+
units = attrs.get("units")
685+
if isinstance(units, str) and "since" in units:
685686
units = pop_to(attrs, encoding, "units")
686687
calendar = pop_to(attrs, encoding, "calendar")
687688
dtype = _decode_cf_datetime_dtype(data, units, calendar, self.use_cftime)

xarray/conventions.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,8 @@ def _update_bounds_attributes(variables):
407407
# For all time variables with bounds
408408
for v in variables.values():
409409
attrs = v.attrs
410-
has_date_units = "units" in attrs and "since" in attrs["units"]
410+
units = attrs.get("units")
411+
has_date_units = isinstance(units, str) and "since" in units
411412
if has_date_units and "bounds" in attrs:
412413
if attrs["bounds"] in variables:
413414
bounds_attrs = variables[attrs["bounds"]].attrs

xarray/tests/test_coding_times.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,3 +1167,11 @@ def test_decode_0size_datetime(use_cftime):
11671167
use_cftime=use_cftime,
11681168
)
11691169
np.testing.assert_equal(expected, actual)
1170+
1171+
1172+
@requires_cftime
1173+
def test_scalar_unit() -> None:
1174+
# test that a scalar units (often NaN when using to_netcdf) does not raise an error
1175+
variable = Variable(("x", "y"), np.array([[0, 1], [2, 3]]), {"units": np.nan})
1176+
result = coding.times.CFDatetimeCoder().decode(variable)
1177+
assert np.isnan(result.attrs["units"])

xarray/tests/test_conventions.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,3 +467,11 @@ def test_decode_cf_variable_cftime():
467467
decoded = conventions.decode_cf_variable("time", variable)
468468
assert decoded.encoding == {}
469469
assert_identical(decoded, variable)
470+
471+
472+
def test_scalar_units() -> None:
473+
# test that scalar units does not raise an exception
474+
var = Variable(["t"], [np.nan, np.nan, 2], {"units": np.nan})
475+
476+
actual = conventions.decode_cf_variable("t", var)
477+
assert_identical(actual, var)

0 commit comments

Comments
 (0)