From f9f4c730254073f0f5a8fce65f4bbaa0eefec5fd Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Wed, 31 Jan 2024 18:42:28 +0100 Subject: [PATCH] Fix multiindex level serialization after reset_index (#8672) * fix serialize multi-index level coord after reset * add regression test * update what's new --------- Co-authored-by: Deepak Cherian --- doc/whats-new.rst | 3 +++ xarray/conventions.py | 18 +++++++++++------- xarray/tests/test_backends.py | 5 +++++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index f5e1efadef5..c8ad4f21215 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -43,6 +43,9 @@ Deprecations Bug fixes ~~~~~~~~~ +- Fixed a regression that prevented multi-index level coordinates being + serialized after resetting or dropping the multi-index (:issue:`8628`, :pull:`8672`). + By `Benoit Bovy `_. - Fix bug with broadcasting when wrapping array API-compliant classes. (:issue:`8665`, :pull:`8669`) By `Tom Nicholas `_. - Ensure :py:meth:`DataArray.unstack` works when wrapping array API-compliant classes. (:issue:`8666`, :pull:`8668`) diff --git a/xarray/conventions.py b/xarray/conventions.py index 1d8e81e1bf2..61d0cc5e385 100644 --- a/xarray/conventions.py +++ b/xarray/conventions.py @@ -16,7 +16,7 @@ ) from xarray.core.pycompat import is_duck_dask_array from xarray.core.utils import emit_user_level_warning -from xarray.core.variable import Variable +from xarray.core.variable import IndexVariable, Variable CF_RELATED_DATA = ( "bounds", @@ -84,13 +84,17 @@ def _infer_dtype(array, name=None): def ensure_not_multiindex(var: Variable, name: T_Name = None) -> None: + # only the pandas multi-index dimension coordinate cannot be serialized (tuple values) if isinstance(var._data, indexing.PandasMultiIndexingAdapter): - raise NotImplementedError( - f"variable {name!r} is a MultiIndex, which cannot yet be " - "serialized. Instead, either use reset_index() " - "to convert MultiIndex levels into coordinate variables instead " - "or use https://cf-xarray.readthedocs.io/en/latest/coding.html." - ) + if name is None and isinstance(var, IndexVariable): + name = var.name + if var.dims == (name,): + raise NotImplementedError( + f"variable {name!r} is a MultiIndex, which cannot yet be " + "serialized. Instead, either use reset_index() " + "to convert MultiIndex levels into coordinate variables instead " + "or use https://cf-xarray.readthedocs.io/en/latest/coding.html." + ) def _copy_with_dtype(data, dtype: np.typing.DTypeLike): diff --git a/xarray/tests/test_backends.py b/xarray/tests/test_backends.py index cbffa7c53ec..0eaa7ee7361 100644 --- a/xarray/tests/test_backends.py +++ b/xarray/tests/test_backends.py @@ -1246,6 +1246,11 @@ def test_multiindex_not_implemented(self) -> None: with self.roundtrip(ds): pass + # regression GH8628 (can serialize reset multi-index level coordinates) + ds_reset = ds.reset_index("x") + with self.roundtrip(ds_reset) as actual: + assert_identical(actual, ds_reset) + class NetCDFBase(CFEncodedBase): """Tests for all netCDF3 and netCDF4 backends."""