2
2
3
3
import collections .abc
4
4
import copy
5
+ import inspect
5
6
from collections import defaultdict
6
- from collections .abc import Hashable , Iterable , Iterator , Mapping , Sequence
7
- from typing import TYPE_CHECKING , Any , Generic , TypeVar , cast
7
+ from collections .abc import Callable , Hashable , Iterable , Iterator , Mapping , Sequence
8
+ from typing import TYPE_CHECKING , Any , Generic , TypeVar , cast , overload
8
9
9
10
import numpy as np
10
11
import pandas as pd
@@ -348,7 +349,15 @@ def reindex_like(self, other: Self) -> dict[Hashable, Any]:
348
349
"""
349
350
raise NotImplementedError (f"{ self !r} doesn't support re-indexing labels" )
350
351
351
- def equals (self , other : Index ) -> bool :
352
+ @overload
353
+ def equals (self , other : Index ) -> bool : ...
354
+
355
+ @overload
356
+ def equals (
357
+ self , other : Index , * , exclude : frozenset [Hashable ] | None = None
358
+ ) -> bool : ...
359
+
360
+ def equals (self , other : Index , ** kwargs ) -> bool :
352
361
"""Compare this index with another index of the same type.
353
362
354
363
Implementation is optional but required in order to support alignment.
@@ -357,11 +366,22 @@ def equals(self, other: Index) -> bool:
357
366
----------
358
367
other : Index
359
368
The other Index object to compare with this object.
369
+ exclude : frozenset of hashable, optional
370
+ Dimensions excluded from checking. It is None by default, (i.e.,
371
+ when this method is not called in the context of alignment). For a
372
+ n-dimensional index this option allows an Index to optionally ignore
373
+ any dimension in ``exclude`` when comparing ``self`` with ``other``.
374
+ For a 1-dimensional index this kwarg can be safely ignored, as this
375
+ method is not called when all of the index's dimensions are also
376
+ excluded from alignment (note: the index's dimensions correspond to
377
+ the union of the dimensions of all coordinate variables associated
378
+ with this index).
360
379
361
380
Returns
362
381
-------
363
382
is_equal : bool
364
383
``True`` if the indexes are equal, ``False`` otherwise.
384
+
365
385
"""
366
386
raise NotImplementedError ()
367
387
@@ -863,7 +883,7 @@ def sel(
863
883
864
884
return IndexSelResult ({self .dim : indexer })
865
885
866
- def equals (self , other : Index ):
886
+ def equals (self , other : Index , * , exclude : frozenset [ Hashable ] | None = None ):
867
887
if not isinstance (other , PandasIndex ):
868
888
return False
869
889
return self .index .equals (other .index ) and self .dim == other .dim
@@ -1542,10 +1562,12 @@ def sel(
1542
1562
1543
1563
return IndexSelResult (results )
1544
1564
1545
- def equals (self , other : Index ) -> bool :
1565
+ def equals (
1566
+ self , other : Index , * , exclude : frozenset [Hashable ] | None = None
1567
+ ) -> bool :
1546
1568
if not isinstance (other , CoordinateTransformIndex ):
1547
1569
return False
1548
- return self .transform .equals (other .transform )
1570
+ return self .transform .equals (other .transform , exclude = exclude )
1549
1571
1550
1572
def rename (
1551
1573
self ,
@@ -1925,6 +1947,36 @@ def default_indexes(
1925
1947
return indexes
1926
1948
1927
1949
1950
+ def _wrap_index_equals (
1951
+ index : Index ,
1952
+ ) -> Callable [[Index , frozenset [Hashable ]], bool ]:
1953
+ # TODO: remove this Index.equals() wrapper (backward compatibility)
1954
+
1955
+ sig = inspect .signature (index .equals )
1956
+
1957
+ if len (sig .parameters ) == 1 :
1958
+ index_cls_name = type (index ).__module__ + "." + type (index ).__qualname__
1959
+ emit_user_level_warning (
1960
+ f"the signature ``{ index_cls_name } .equals(self, other)`` is deprecated. "
1961
+ f"Please update it to "
1962
+ f"``{ index_cls_name } .equals(self, other, *, exclude=None)`` "
1963
+ "or kindly ask the maintainers of ``{index_cls_name}`` to do it. "
1964
+ "See documentation of xarray.Index.equals() for more info." ,
1965
+ FutureWarning ,
1966
+ )
1967
+ exclude_kwarg = False
1968
+ else :
1969
+ exclude_kwarg = True
1970
+
1971
+ def equals_wrapper (other : Index , exclude : frozenset [Hashable ]) -> bool :
1972
+ if exclude_kwarg :
1973
+ return index .equals (other , exclude = exclude )
1974
+ else :
1975
+ return index .equals (other )
1976
+
1977
+ return equals_wrapper
1978
+
1979
+
1928
1980
def indexes_equal (
1929
1981
index : Index ,
1930
1982
other_index : Index ,
@@ -1966,6 +2018,7 @@ def indexes_equal(
1966
2018
1967
2019
def indexes_all_equal (
1968
2020
elements : Sequence [tuple [Index , dict [Hashable , Variable ]]],
2021
+ exclude_dims : frozenset [Hashable ],
1969
2022
) -> bool :
1970
2023
"""Check if indexes are all equal.
1971
2024
@@ -1990,9 +2043,11 @@ def check_variables():
1990
2043
1991
2044
same_type = all (type (indexes [0 ]) is type (other_idx ) for other_idx in indexes [1 :])
1992
2045
if same_type :
2046
+ index_equals_func = _wrap_index_equals (indexes [0 ])
1993
2047
try :
1994
2048
not_equal = any (
1995
- not indexes [0 ].equals (other_idx ) for other_idx in indexes [1 :]
2049
+ not index_equals_func (other_idx , exclude_dims )
2050
+ for other_idx in indexes [1 :]
1996
2051
)
1997
2052
except NotImplementedError :
1998
2053
not_equal = check_variables ()
0 commit comments