From 52a73711968337f5e623780facfb0d0d6d636633 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 5 Jul 2024 03:26:12 +0200 Subject: [PATCH] avoid converting custom indexes to pandas indexes when formatting coordinate diffs (#9157) * use `.xindexes` to construct the diff * check that the indexes are never converted to pandas indexes * deduplicate the various custom index dummy implementations * whats-new [skip-rtd] * fill in the pr number --------- Co-authored-by: Deepak Cherian --- doc/whats-new.rst | 2 + xarray/core/formatting.py | 4 +- xarray/tests/test_formatting.py | 76 ++++++++++++++++++++++++--------- 3 files changed, 60 insertions(+), 22 deletions(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 685cdf28194..753586c32c2 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -37,6 +37,8 @@ Deprecations Bug fixes ~~~~~~~~~ +- Don't convert custom indexes to ``pandas`` indexes when computing a diff (:pull:`9157`) + By `Justus Magin `_. - Make :py:func:`testing.assert_allclose` work with numpy 2.0 (:issue:`9165`, :pull:`9166`). By `Pontus Lurcock `_. - Allow diffing objects with array attributes on variables (:issue:`9153`, :pull:`9169`). diff --git a/xarray/core/formatting.py b/xarray/core/formatting.py index 6dca4eba8e8..6571b288fae 100644 --- a/xarray/core/formatting.py +++ b/xarray/core/formatting.py @@ -898,8 +898,8 @@ def diff_coords_repr(a, b, compat, col_width=None): "Coordinates", summarize_variable, col_width=col_width, - a_indexes=a.indexes, - b_indexes=b.indexes, + a_indexes=a.xindexes, + b_indexes=b.xindexes, ) diff --git a/xarray/tests/test_formatting.py b/xarray/tests/test_formatting.py index 6c49ab456f6..9d0eb81bace 100644 --- a/xarray/tests/test_formatting.py +++ b/xarray/tests/test_formatting.py @@ -10,9 +10,20 @@ import xarray as xr from xarray.core import formatting from xarray.core.datatree import DataTree # TODO: Remove when can do xr.DataTree +from xarray.core.indexes import Index from xarray.tests import requires_cftime, requires_dask, requires_netCDF4 +class CustomIndex(Index): + names: tuple[str, ...] + + def __init__(self, names: tuple[str, ...]): + self.names = names + + def __repr__(self): + return f"CustomIndex(coords={self.names})" + + class TestFormatting: def test_get_indexer_at_least_n_items(self) -> None: cases = [ @@ -219,17 +230,6 @@ def test_attribute_repr(self) -> None: assert "\t" not in tabs def test_index_repr(self) -> None: - from xarray.core.indexes import Index - - class CustomIndex(Index): - names: tuple[str, ...] - - def __init__(self, names: tuple[str, ...]): - self.names = names - - def __repr__(self): - return f"CustomIndex(coords={self.names})" - coord_names = ("x", "y") index = CustomIndex(coord_names) names = ("x",) @@ -258,15 +258,6 @@ def _repr_inline_(self, max_width: int): ), ) def test_index_repr_grouping(self, names) -> None: - from xarray.core.indexes import Index - - class CustomIndex(Index): - def __init__(self, names): - self.names = names - - def __repr__(self): - return f"CustomIndex(coords={self.names})" - index = CustomIndex(names) normal = formatting.summarize_index(names, index, col_width=20) @@ -337,6 +328,51 @@ def test_diff_array_repr(self) -> None: # depending on platform, dtype may not be shown in numpy array repr assert actual == expected.replace(", dtype=int64", "") + da_a = xr.DataArray( + np.array([[1, 2, 3], [4, 5, 6]], dtype="int8"), + dims=("x", "y"), + coords=xr.Coordinates( + { + "x": np.array([True, False], dtype="bool"), + "y": np.array([1, 2, 3], dtype="int16"), + }, + indexes={"y": CustomIndex(("y",))}, + ), + ) + + da_b = xr.DataArray( + np.array([1, 2], dtype="int8"), + dims="x", + coords=xr.Coordinates( + { + "x": np.array([True, False], dtype="bool"), + "label": ("x", np.array([1, 2], dtype="int16")), + }, + indexes={"label": CustomIndex(("label",))}, + ), + ) + + expected = dedent( + """\ + Left and right DataArray objects are not equal + Differing dimensions: + (x: 2, y: 3) != (x: 2) + Differing values: + L + array([[1, 2, 3], + [4, 5, 6]], dtype=int8) + R + array([1, 2], dtype=int8) + Coordinates only on the left object: + * y (y) int16 6B 1 2 3 + Coordinates only on the right object: + * label (x) int16 4B 1 2 + """.rstrip() + ) + + actual = formatting.diff_array_repr(da_a, da_b, "equals") + assert actual == expected + va = xr.Variable( "x", np.array([1, 2, 3], dtype="int64"), {"title": "test Variable"} )