From 758ddc32c196c81ee3caf459abc067b0f4225495 Mon Sep 17 00:00:00 2001 From: Chirag Gupta <103719146+chiruu12@users.noreply.github.com> Date: Sat, 5 Sep 2026 15:17:39 +0530 Subject: [PATCH] return a copy from get_index --- doc/whats-new.rst | 4 ++++ xarray/core/common.py | 6 +++++- xarray/tests/test_dataarray.py | 11 +++++++++++ xarray/tests/test_dataset.py | 9 +++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index e763ce03907..d43707627b4 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -114,6 +114,10 @@ Bug Fixes type error when applying reduction methods, due to the reduction methods being dynamically generated (:issue:`8136`). By `Andrew Scherer `_. +- :py:meth:`DataArray.get_index` and :py:meth:`Dataset.get_index` now return a + shallow copy of the stored index, so setting ``.name`` on the result no longer + renames the coordinate of the object it came from (:issue:`2949`). + By `Chirag Gupta `_. .. _`pandas-dev/pandas#64793`: https://github.com/pandas-dev/pandas/pull/64793 diff --git a/xarray/core/common.py b/xarray/core/common.py index 4c506b05325..332571a9742 100644 --- a/xarray/core/common.py +++ b/xarray/core/common.py @@ -508,7 +508,11 @@ def get_index(self, key: Hashable) -> pd.Index: raise KeyError(key) try: - return self._indexes[key].to_pandas_index() + # Shallow copy so that renaming the returned index, which pandas + # allows in place, cannot reach back into this object's own index. + # It shares the underlying data, and xarray already relies on that + # being free (see IndexVariable._to_index). + return self._indexes[key].to_pandas_index().copy(deep=False) except KeyError: return pd.Index(range(self.sizes[key]), name=key) diff --git a/xarray/tests/test_dataarray.py b/xarray/tests/test_dataarray.py index f94d221a758..995dac5cc2e 100644 --- a/xarray/tests/test_dataarray.py +++ b/xarray/tests/test_dataarray.py @@ -200,6 +200,17 @@ def test_get_index(self) -> None: with pytest.raises(KeyError): array.get_index("z") + def test_get_index_is_not_a_view_of_the_stored_index(self) -> None: + # GH2949: a pandas index lets its name be set in place, so handing out + # the stored object let a caller rename this array's own coordinate. + array = DataArray(np.zeros(2), coords={"x": ["a", "b"]}, dims=["x"]) + + array.get_index("x").name = "renamed" + array.to_index().name = "renamed too" + array.to_series().index.name = "and again" + + assert array.get_index("x").name == "x" + def test_get_index_size_zero(self) -> None: array = DataArray(np.zeros((0,)), dims=["x"]) actual = array.get_index("x") diff --git a/xarray/tests/test_dataset.py b/xarray/tests/test_dataset.py index 883a6dc89b7..e44efa59890 100644 --- a/xarray/tests/test_dataset.py +++ b/xarray/tests/test_dataset.py @@ -778,6 +778,15 @@ def test_asarray(self) -> None: with pytest.raises(TypeError, match=r"cannot directly convert"): np.asarray(ds) + def test_get_index_is_not_a_view_of_the_stored_index(self) -> None: + # GH2949, the Dataset half: get_index is inherited from + # DataWithCoords, so Dataset handed out the stored index too. + ds = Dataset({"v": ("x", np.zeros(2))}, coords={"x": ["a", "b"]}) + + ds.get_index("x").name = "renamed" + + assert ds.get_index("x").name == "x" + def test_get_index(self) -> None: ds = Dataset({"foo": (("x", "y"), np.zeros((2, 3)))}, coords={"x": ["a", "b"]}) assert ds.get_index("x").equals(pd.Index(["a", "b"]))