From ad56e7b3d78df69005098b87614f96901203720d Mon Sep 17 00:00:00 2001 From: Deepak Cherian Date: Fri, 29 Mar 2024 21:14:51 -0600 Subject: [PATCH 1/5] Add invariant check for #8646 --- xarray/testing/assertions.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xarray/testing/assertions.py b/xarray/testing/assertions.py index 6418eb79b8b..0a89da3f70e 100644 --- a/xarray/testing/assertions.py +++ b/xarray/testing/assertions.py @@ -268,6 +268,10 @@ def _assert_indexes_invariants_checks( } assert indexes.keys() <= index_vars, (set(indexes), index_vars) + for k, v in possible_coord_variables.items(): + if isinstance(v, IndexVariable): + assert k == v.name, (k, v.name) + # check pandas index wrappers vs. coordinate data adapters for k, index in indexes.items(): if isinstance(index, PandasIndex): From 96e362615781674c9529c009ed8ffb02e33ff4b6 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Thu, 4 Apr 2024 16:44:56 +0200 Subject: [PATCH 2/5] nit refactor --- xarray/testing/assertions.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/xarray/testing/assertions.py b/xarray/testing/assertions.py index 0a89da3f70e..86b7bbdb1e9 100644 --- a/xarray/testing/assertions.py +++ b/xarray/testing/assertions.py @@ -264,13 +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 possible_coord_variables.items(): - if isinstance(v, IndexVariable): - assert k == v.name, (k, v.name) + 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(): @@ -287,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, ( From 00f538245db1a9ecc11e5391285d067b1b92088e Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Thu, 4 Apr 2024 16:45:35 +0200 Subject: [PATCH 3/5] allow IndexVariable.name differ from dim name --- xarray/core/variable.py | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) 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: From 3f1d4a734fb00c28ca63359da93f66b9455c353b Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Thu, 4 Apr 2024 16:46:09 +0200 Subject: [PATCH 4/5] fix multi-index level variable name --- xarray/core/indexes.py | 1 + 1 file changed, 1 insertion(+) diff --git a/xarray/core/indexes.py b/xarray/core/indexes.py index e71c4a6f073..8b2d21d15e5 100644 --- a/xarray/core/indexes.py +++ b/xarray/core/indexes.py @@ -1153,6 +1153,7 @@ def create_variables( attrs=attrs, encoding=encoding, fastpath=True, + name=name, ) return index_vars From 2083caf2d117e5c80b99d6e9366d9f4a90b1b8ef Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Fri, 5 Apr 2024 09:12:14 +0200 Subject: [PATCH 5/5] fix single pandas index non-dimension coord name --- xarray/core/indexes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/indexes.py b/xarray/core/indexes.py index 8b2d21d15e5..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: