Skip to content

Commit b6b9f3f

Browse files
jbrockmendeljreback
authored andcommitted
Pin correct names to wrapped Index comparison methods (#18397)
1 parent 18b2569 commit b6b9f3f

File tree

6 files changed

+57
-34
lines changed

6 files changed

+57
-34
lines changed

pandas/core/indexes/base.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from pandas._libs.lib import is_datetime_array
1010
from pandas._libs.tslibs import parsing
1111

12-
from pandas.compat import range, u
12+
from pandas.compat import range, u, set_function_name
1313
from pandas.compat.numpy import function as nv
1414
from pandas import compat
1515

@@ -3893,7 +3893,8 @@ def _evaluate_compare(self, other):
38933893
except TypeError:
38943894
return result
38953895

3896-
return _evaluate_compare
3896+
name = '__{name}__'.format(name=op.__name__)
3897+
return set_function_name(_evaluate_compare, name, cls)
38973898

38983899
cls.__eq__ = _make_compare(operator.eq)
38993900
cls.__ne__ = _make_compare(operator.ne)

pandas/core/indexes/category.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,7 @@ def _codes_for_groupby(self, sort):
722722
def _add_comparison_methods(cls):
723723
""" add in comparison methods """
724724

725-
def _make_compare(op):
725+
def _make_compare(opname):
726726
def _evaluate_compare(self, other):
727727

728728
# if we have a Categorical type, then must have the same
@@ -745,9 +745,9 @@ def _evaluate_compare(self, other):
745745
"have the same categories and ordered "
746746
"attributes")
747747

748-
return getattr(self.values, op)(other)
748+
return getattr(self.values, opname)(other)
749749

750-
return _evaluate_compare
750+
return compat.set_function_name(_evaluate_compare, opname, cls)
751751

752752
cls.__eq__ = _make_compare('__eq__')
753753
cls.__ne__ = _make_compare('__ne__')

pandas/core/indexes/datetimes.py

+18-13
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def f(self):
9898
return property(f)
9999

100100

101-
def _dt_index_cmp(opname, nat_result=False):
101+
def _dt_index_cmp(opname, cls, nat_result=False):
102102
"""
103103
Wrap comparison operations to convert datetime-like to datetime64
104104
"""
@@ -135,7 +135,7 @@ def wrapper(self, other):
135135
return result
136136
return Index(result)
137137

138-
return wrapper
138+
return compat.set_function_name(wrapper, opname, cls)
139139

140140

141141
def _ensure_datetime64(other):
@@ -277,12 +277,15 @@ def _join_i8_wrapper(joinf, **kwargs):
277277
libjoin.left_join_indexer_unique_int64, with_indexers=False)
278278
_arrmap = None
279279

280-
__eq__ = _dt_index_cmp('__eq__')
281-
__ne__ = _dt_index_cmp('__ne__', nat_result=True)
282-
__lt__ = _dt_index_cmp('__lt__')
283-
__gt__ = _dt_index_cmp('__gt__')
284-
__le__ = _dt_index_cmp('__le__')
285-
__ge__ = _dt_index_cmp('__ge__')
280+
@classmethod
281+
def _add_comparison_methods(cls):
282+
""" add in comparison methods """
283+
cls.__eq__ = _dt_index_cmp('__eq__', cls)
284+
cls.__ne__ = _dt_index_cmp('__ne__', cls, nat_result=True)
285+
cls.__lt__ = _dt_index_cmp('__lt__', cls)
286+
cls.__gt__ = _dt_index_cmp('__gt__', cls)
287+
cls.__le__ = _dt_index_cmp('__le__', cls)
288+
cls.__ge__ = _dt_index_cmp('__ge__', cls)
286289

287290
_engine_type = libindex.DatetimeEngine
288291

@@ -1599,14 +1602,15 @@ def slice_indexer(self, start=None, end=None, step=None, kind=None):
15991602
else:
16001603
raise
16011604

1602-
# alias to offset
1603-
def _get_freq(self):
1605+
@property
1606+
def freq(self):
1607+
"""get/set the frequency of the Index"""
16041608
return self.offset
16051609

1606-
def _set_freq(self, value):
1610+
@freq.setter
1611+
def freq(self, value):
1612+
"""get/set the frequency of the Index"""
16071613
self.offset = value
1608-
freq = property(fget=_get_freq, fset=_set_freq,
1609-
doc="get/set the frequency of the Index")
16101614

16111615
year = _field_accessor('year', 'Y', "The year of the datetime")
16121616
month = _field_accessor('month', 'M',
@@ -2014,6 +2018,7 @@ def to_julian_date(self):
20142018
) / 24.0)
20152019

20162020

2021+
DatetimeIndex._add_comparison_methods()
20172022
DatetimeIndex._add_numeric_methods_disabled()
20182023
DatetimeIndex._add_logical_methods_disabled()
20192024
DatetimeIndex._add_datetimelike_methods()

pandas/core/indexes/period.py

+13-8
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def dt64arr_to_periodarr(data, freq, tz):
7777
_DIFFERENT_FREQ_INDEX = period._DIFFERENT_FREQ_INDEX
7878

7979

80-
def _period_index_cmp(opname, nat_result=False):
80+
def _period_index_cmp(opname, cls, nat_result=False):
8181
"""
8282
Wrap comparison operations to convert datetime-like to datetime64
8383
"""
@@ -115,7 +115,8 @@ def wrapper(self, other):
115115
result[self._isnan] = nat_result
116116

117117
return result
118-
return wrapper
118+
119+
return compat.set_function_name(wrapper, opname, cls)
119120

120121

121122
def _new_PeriodIndex(cls, **d):
@@ -227,12 +228,15 @@ class PeriodIndex(DatelikeOps, DatetimeIndexOpsMixin, Int64Index):
227228

228229
_engine_type = libindex.PeriodEngine
229230

230-
__eq__ = _period_index_cmp('__eq__')
231-
__ne__ = _period_index_cmp('__ne__', nat_result=True)
232-
__lt__ = _period_index_cmp('__lt__')
233-
__gt__ = _period_index_cmp('__gt__')
234-
__le__ = _period_index_cmp('__le__')
235-
__ge__ = _period_index_cmp('__ge__')
231+
@classmethod
232+
def _add_comparison_methods(cls):
233+
""" add in comparison methods """
234+
cls.__eq__ = _period_index_cmp('__eq__', cls)
235+
cls.__ne__ = _period_index_cmp('__ne__', cls, nat_result=True)
236+
cls.__lt__ = _period_index_cmp('__lt__', cls)
237+
cls.__gt__ = _period_index_cmp('__gt__', cls)
238+
cls.__le__ = _period_index_cmp('__le__', cls)
239+
cls.__ge__ = _period_index_cmp('__ge__', cls)
236240

237241
def __new__(cls, data=None, ordinal=None, freq=None, start=None, end=None,
238242
periods=None, copy=False, name=None, tz=None, dtype=None,
@@ -1106,6 +1110,7 @@ def tz_localize(self, tz, infer_dst=False):
11061110
raise NotImplementedError("Not yet implemented for PeriodIndex")
11071111

11081112

1113+
PeriodIndex._add_comparison_methods()
11091114
PeriodIndex._add_numeric_methods_disabled()
11101115
PeriodIndex._add_logical_methods_disabled()
11111116
PeriodIndex._add_datetimelike_methods()

pandas/core/indexes/timedeltas.py

+12-8
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def f(self):
5252
return property(f)
5353

5454

55-
def _td_index_cmp(opname, nat_result=False):
55+
def _td_index_cmp(opname, cls, nat_result=False):
5656
"""
5757
Wrap comparison operations to convert timedelta-like to timedelta64
5858
"""
@@ -93,7 +93,7 @@ def wrapper(self, other):
9393
return result
9494
return Index(result)
9595

96-
return wrapper
96+
return compat.set_function_name(wrapper, opname, cls)
9797

9898

9999
class TimedeltaIndex(DatetimeIndexOpsMixin, TimelikeOps, Int64Index):
@@ -180,12 +180,15 @@ def _join_i8_wrapper(joinf, **kwargs):
180180
_datetimelike_methods = ["to_pytimedelta", "total_seconds",
181181
"round", "floor", "ceil"]
182182

183-
__eq__ = _td_index_cmp('__eq__')
184-
__ne__ = _td_index_cmp('__ne__', nat_result=True)
185-
__lt__ = _td_index_cmp('__lt__')
186-
__gt__ = _td_index_cmp('__gt__')
187-
__le__ = _td_index_cmp('__le__')
188-
__ge__ = _td_index_cmp('__ge__')
183+
@classmethod
184+
def _add_comparison_methods(cls):
185+
""" add in comparison methods """
186+
cls.__eq__ = _td_index_cmp('__eq__', cls)
187+
cls.__ne__ = _td_index_cmp('__ne__', cls, nat_result=True)
188+
cls.__lt__ = _td_index_cmp('__lt__', cls)
189+
cls.__gt__ = _td_index_cmp('__gt__', cls)
190+
cls.__le__ = _td_index_cmp('__le__', cls)
191+
cls.__ge__ = _td_index_cmp('__ge__', cls)
189192

190193
_engine_type = libindex.TimedeltaEngine
191194

@@ -912,6 +915,7 @@ def delete(self, loc):
912915
return TimedeltaIndex(new_tds, name=self.name, freq=freq)
913916

914917

918+
TimedeltaIndex._add_comparison_methods()
915919
TimedeltaIndex._add_numeric_methods()
916920
TimedeltaIndex._add_logical_methods_disabled()
917921
TimedeltaIndex._add_datetimelike_methods()

pandas/tests/indexes/test_base.py

+8
Original file line numberDiff line numberDiff line change
@@ -2174,3 +2174,11 @@ class TestIndexUtils(object):
21742174
def test_ensure_index_from_sequences(self, data, names, expected):
21752175
result = _ensure_index_from_sequences(data, names)
21762176
tm.assert_index_equal(result, expected)
2177+
2178+
2179+
@pytest.mark.parametrize('opname', ['eq', 'ne', 'le', 'lt', 'ge', 'gt'])
2180+
def test_generated_op_names(opname, indices):
2181+
index = indices
2182+
opname = '__{name}__'.format(name=opname)
2183+
method = getattr(index, opname)
2184+
assert method.__name__ == opname

0 commit comments

Comments
 (0)