diff --git a/doc/whats-new.rst b/doc/whats-new.rst index f6618e060c7..f8780cdef21 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -30,6 +30,12 @@ Bug Fixes differ from the dtype returned by the matching numpy-backed bottleneck path, notably ``object`` instead of ``float64`` for boolean inputs. By `Matthew Rocklin `_. +- Fixed a :py:class:`KeyError` when building a multi-index (e.g. via + :py:meth:`Dataset.stack` or :py:meth:`Dataset.set_index`) from levels whose + name is falsy but valid, such as an empty string ``""``. Such names were + incorrectly replaced by the default ``{dim}_level_{i}`` name instead of being + preserved. + By `Kropiunig `_. Documentation diff --git a/xarray/core/indexes.py b/xarray/core/indexes.py index 2242e57e482..8aa952075f6 100644 --- a/xarray/core/indexes.py +++ b/xarray/core/indexes.py @@ -1038,7 +1038,7 @@ def __init__(self, array: Any, dim: Hashable, level_coords_dtype: Any = None): # default index level names names = [] for i, idx in enumerate(self.index.levels): - name = idx.name or f"{dim}_level_{i}" + name = idx.name if idx.name is not None else f"{dim}_level_{i}" if name == dim: raise ValueError( f"conflicting multi-index level name {name!r} with dimension {dim!r}" diff --git a/xarray/tests/test_indexes.py b/xarray/tests/test_indexes.py index 94adcc3b935..085a986dc3c 100644 --- a/xarray/tests/test_indexes.py +++ b/xarray/tests/test_indexes.py @@ -354,6 +354,12 @@ def test_constructor(self) -> None: index = PandasMultiIndex(pd_idx, "x") assert list(index.index.names) == ["x_level_0", "x_level_1"] + # a falsy but valid level name (e.g. "") must be preserved rather than + # replaced by the default ``{dim}_level_{i}`` name + pd_idx = pd.MultiIndex.from_arrays([foo_data, bar_data], names=("", "bar")) + index = PandasMultiIndex(pd_idx, "x") + assert list(index.index.names) == ["", "bar"] + def test_from_variables(self) -> None: v_level1 = xr.Variable( "x", [1, 2, 3], attrs={"unit": "m"}, encoding={"dtype": np.int32}