diff --git a/doc/whats-new.rst b/doc/whats-new.rst index c644f7615b7..00e969df160 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -71,7 +71,8 @@ Bug fixes - Warn and return bytes undecoded in case of UnicodeDecodeError in h5netcdf-backend (:issue:`5563`, :pull:`8874`). By `Kai Mühlbauer `_. - +- Fix a regression when saving dropped multi-indexes with the zarr backend (:pull:`8809`). + By `Sam Levang `_. Documentation ~~~~~~~~~~~~~ diff --git a/xarray/backends/common.py b/xarray/backends/common.py index f318b4dd42f..e094d35ec4b 100644 --- a/xarray/backends/common.py +++ b/xarray/backends/common.py @@ -329,11 +329,11 @@ def encode(self, variables, attributes): attributes : dict-like """ - variables = {k: self.encode_variable(v) for k, v in variables.items()} + variables = {k: self.encode_variable(v, k) for k, v in variables.items()} attributes = {k: self.encode_attribute(v) for k, v in attributes.items()} return variables, attributes - def encode_variable(self, v): + def encode_variable(self, v, name: str | None = None): """encode one variable""" return v @@ -480,7 +480,7 @@ def encode(self, variables, attributes): # All NetCDF files get CF encoded by default, without this attempting # to write times, for example, would fail. variables, attributes = cf_encoder(variables, attributes) - variables = {k: self.encode_variable(v) for k, v in variables.items()} + variables = {k: self.encode_variable(v, k) for k, v in variables.items()} attributes = {k: self.encode_attribute(v) for k, v in attributes.items()} return variables, attributes diff --git a/xarray/backends/h5netcdf_.py b/xarray/backends/h5netcdf_.py index 71463193939..ae297f93f9d 100644 --- a/xarray/backends/h5netcdf_.py +++ b/xarray/backends/h5netcdf_.py @@ -263,7 +263,7 @@ def set_dimension(self, name, length, is_unlimited=False): def set_attribute(self, key, value): self.ds.attrs[key] = value - def encode_variable(self, variable): + def encode_variable(self, variable, name): return _encode_nc4_variable(variable) def prepare_variable( diff --git a/xarray/backends/netCDF4_.py b/xarray/backends/netCDF4_.py index ae86c4ce384..0c9da18b88e 100644 --- a/xarray/backends/netCDF4_.py +++ b/xarray/backends/netCDF4_.py @@ -490,7 +490,7 @@ def set_attribute(self, key, value): else: self.ds.setncattr(key, value) - def encode_variable(self, variable): + def encode_variable(self, variable, name): variable = _force_native_endianness(variable) if self.format == "NETCDF4": variable = _encode_nc4_variable(variable) diff --git a/xarray/backends/scipy_.py b/xarray/backends/scipy_.py index f8c486e512c..c4343d380db 100644 --- a/xarray/backends/scipy_.py +++ b/xarray/backends/scipy_.py @@ -226,7 +226,7 @@ def set_attribute(self, key, value): value = encode_nc3_attr_value(value) setattr(self.ds, key, value) - def encode_variable(self, variable): + def encode_variable(self, variable, name): variable = encode_nc3_variable(variable) return variable diff --git a/xarray/backends/zarr.py b/xarray/backends/zarr.py index 13b1819f206..7c50d072691 100644 --- a/xarray/backends/zarr.py +++ b/xarray/backends/zarr.py @@ -569,8 +569,8 @@ def set_dimensions(self, variables, unlimited_dims=None): def set_attributes(self, attributes): _put_attrs(self.zarr_group, attributes) - def encode_variable(self, variable): - variable = encode_zarr_variable(variable) + def encode_variable(self, variable, name): + variable = encode_zarr_variable(variable, name=name) return variable def encode_attribute(self, a): diff --git a/xarray/tests/test_backends.py b/xarray/tests/test_backends.py index 1d69b3adc63..f80d1e70989 100644 --- a/xarray/tests/test_backends.py +++ b/xarray/tests/test_backends.py @@ -1257,6 +1257,16 @@ def test_multiindex_not_implemented(self) -> None: with self.roundtrip(ds_reset) as actual: assert_identical(actual, ds_reset) + def test_reset_multiindex_as_indexvariable(self) -> None: + # regression noted in https://github.com/xarray-contrib/xeofs/issues/148 + ds = xr.Dataset(coords={"dim1": [1, 2, 3]}) + ds = ds.stack(feature=["dim1"]) + ds_reset = ds.reset_index("feature") + # Convert dim1 back to an IndexVariable, should still be able to serialize + ds_reset["dim1"] = ds_reset.dim1.variable.to_index_variable() + with self.roundtrip(ds_reset) as actual: + assert_identical(actual, ds_reset) + class NetCDFBase(CFEncodedBase): """Tests for all netCDF3 and netCDF4 backends.""" diff --git a/xarray/tests/test_conventions.py b/xarray/tests/test_conventions.py index fdfea3c3fe8..d9f0721de44 100644 --- a/xarray/tests/test_conventions.py +++ b/xarray/tests/test_conventions.py @@ -460,7 +460,7 @@ def test_decode_cf_time_kwargs(self) -> None: class CFEncodedInMemoryStore(WritableCFDataStore, InMemoryDataStore): - def encode_variable(self, var): + def encode_variable(self, var, name): """encode one variable""" coder = coding.strings.EncodedStringCoder(allows_unicode=True) var = coder.encode(var)