diff --git a/xarray/core/indexes.py b/xarray/core/indexes.py index e71c4a6f073..c667124beb7 100644 --- a/xarray/core/indexes.py +++ b/xarray/core/indexes.py @@ -701,7 +701,7 @@ def create_variables( encoding = None data = PandasIndexingAdapter(self.index, dtype=self.coord_dtype) - var = IndexVariable(self.dim, data, attrs=attrs, encoding=encoding) + var = IndexVariable(self.dim, data, attrs=attrs, encoding=encoding, name=name) return {name: var} def to_pandas_index(self) -> pd.Index: @@ -1153,6 +1153,7 @@ def create_variables( attrs=attrs, encoding=encoding, fastpath=True, + name=name, ) return index_vars diff --git a/xarray/core/variable.py b/xarray/core/variable.py index ec284e411fc..b2e97702ecc 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -2590,12 +2590,14 @@ class IndexVariable(Variable): unless another name is given. """ - __slots__ = () + __slots__ = ("_name",) # TODO: PandasIndexingAdapter doesn't match the array api: _data: PandasIndexingAdapter # type: ignore[assignment] - def __init__(self, dims, data, attrs=None, encoding=None, fastpath=False): + def __init__( + self, dims, data, attrs=None, encoding=None, fastpath=False, name=None + ): super().__init__(dims, data, attrs, encoding, fastpath) if self.ndim != 1: raise ValueError(f"{type(self).__name__} objects must be 1-dimensional") @@ -2604,6 +2606,11 @@ def __init__(self, dims, data, attrs=None, encoding=None, fastpath=False): if not isinstance(self._data, PandasIndexingAdapter): self._data = PandasIndexingAdapter(self._data) + if name is None: + self._name = self.dims[0] + else: + self._name = name + def __dask_tokenize__(self) -> object: from dask.base import normalize_token @@ -2753,7 +2760,22 @@ def copy(self, deep: bool = True, data: T_DuckArray | ArrayLike | None = None): attrs = copy.deepcopy(self._attrs) if deep else copy.copy(self._attrs) encoding = copy.deepcopy(self._encoding) if deep else copy.copy(self._encoding) - return self._replace(data=ndata, attrs=attrs, encoding=encoding) + copied = self._replace(data=ndata, attrs=attrs, encoding=encoding) + + return copied + + def _replace( + self, + dims=_default, + data=_default, + attrs=_default, + encoding=_default, + ) -> Self: + replaced = super()._replace( + dims=dims, data=data, attrs=attrs, encoding=encoding + ) + replaced._name = self._name + return replaced def equals(self, other, equiv=None): # if equiv is specified, super up @@ -2825,7 +2847,7 @@ def get_level_variable(self, level): @property def name(self) -> Hashable: - return self.dims[0] + return self._name @name.setter def name(self, value) -> NoReturn: diff --git a/xarray/testing/assertions.py b/xarray/testing/assertions.py index 6418eb79b8b..86b7bbdb1e9 100644 --- a/xarray/testing/assertions.py +++ b/xarray/testing/assertions.py @@ -264,9 +264,15 @@ def _assert_indexes_invariants_checks( } index_vars = { - k for k, v in possible_coord_variables.items() if isinstance(v, IndexVariable) + k: v + for k, v in possible_coord_variables.items() + if isinstance(v, IndexVariable) } - assert indexes.keys() <= index_vars, (set(indexes), index_vars) + index_var_names = set(index_vars) + assert indexes.keys() <= index_var_names, (set(indexes), index_var_names) + + for k, v in index_vars.items(): + assert k == v.name, (k, v.name) # check pandas index wrappers vs. coordinate data adapters for k, index in indexes.items(): @@ -283,7 +289,7 @@ def _assert_indexes_invariants_checks( if isinstance(index, PandasMultiIndex): pd_index = index.index for name in index.index.names: - assert name in possible_coord_variables, (pd_index, index_vars) + assert name in possible_coord_variables, (pd_index, index_var_names) var = possible_coord_variables[name] assert (index.dim,) == var.dims, (pd_index, var) assert index.level_coords_dtype[name] == var.dtype, (