Skip to content

Commit ddb3427

Browse files
jbrockmendeljreback
authored andcommitted
REF: gradually move ExtensionIndex delegation to use inherit_names (#30860)
1 parent a5daff2 commit ddb3427

File tree

4 files changed

+56
-58
lines changed

4 files changed

+56
-58
lines changed

pandas/core/indexes/category.py

+16-14
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,29 @@
2727
import pandas.core.common as com
2828
import pandas.core.indexes.base as ibase
2929
from pandas.core.indexes.base import Index, _index_shared_docs, maybe_extract_name
30-
from pandas.core.indexes.extension import ExtensionIndex
30+
from pandas.core.indexes.extension import ExtensionIndex, inherit_names
3131
import pandas.core.missing as missing
3232
from pandas.core.ops import get_op_result_name
3333

3434
_index_doc_kwargs = dict(ibase._index_doc_kwargs)
3535
_index_doc_kwargs.update(dict(target_klass="CategoricalIndex"))
3636

3737

38-
@accessor.delegate_names(
39-
delegate=Categorical,
40-
accessors=["codes", "categories", "ordered"],
41-
typ="property",
42-
overwrite=True,
38+
@inherit_names(
39+
[
40+
"argsort",
41+
"_internal_get_values",
42+
"tolist",
43+
"codes",
44+
"categories",
45+
"ordered",
46+
"_reverse_indexer",
47+
"searchsorted",
48+
"is_dtype_equal",
49+
"min",
50+
"max",
51+
],
52+
Categorical,
4353
)
4454
@accessor.delegate_names(
4555
delegate=Categorical,
@@ -52,14 +62,6 @@
5262
"set_categories",
5363
"as_ordered",
5464
"as_unordered",
55-
"min",
56-
"max",
57-
"is_dtype_equal",
58-
"tolist",
59-
"_internal_get_values",
60-
"_reverse_indexer",
61-
"searchsorted",
62-
"argsort",
6365
],
6466
typ="method",
6567
overwrite=True,

pandas/core/indexes/extension.py

+24-5
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from pandas.core.ops import get_op_result_name
1717

1818

19-
def inherit_from_data(name: str, delegate, cache: bool = False):
19+
def inherit_from_data(name: str, delegate, cache: bool = False, wrap: bool = False):
2020
"""
2121
Make an alias for a method of the underlying ExtensionArray.
2222
@@ -27,6 +27,8 @@ def inherit_from_data(name: str, delegate, cache: bool = False):
2727
delegate : class
2828
cache : bool, default False
2929
Whether to convert wrapped properties into cache_readonly
30+
wrap : bool, default False
31+
Whether to wrap the inherited result in an Index.
3032
3133
Returns
3234
-------
@@ -37,12 +39,23 @@ def inherit_from_data(name: str, delegate, cache: bool = False):
3739

3840
if isinstance(attr, property):
3941
if cache:
40-
method = cache_readonly(attr.fget)
42+
43+
def cached(self):
44+
return getattr(self._data, name)
45+
46+
cached.__name__ = name
47+
cached.__doc__ = attr.__doc__
48+
method = cache_readonly(cached)
4149

4250
else:
4351

4452
def fget(self):
45-
return getattr(self._data, name)
53+
result = getattr(self._data, name)
54+
if wrap:
55+
if isinstance(result, type(self._data)):
56+
return type(self)._simple_new(result, name=self.name)
57+
return Index(result, name=self.name)
58+
return result
4659

4760
def fset(self, value):
4861
setattr(self._data, name, value)
@@ -60,14 +73,18 @@ def fset(self, value):
6073

6174
def method(self, *args, **kwargs):
6275
result = attr(self._data, *args, **kwargs)
76+
if wrap:
77+
if isinstance(result, type(self._data)):
78+
return type(self)._simple_new(result, name=self.name)
79+
return Index(result, name=self.name)
6380
return result
6481

6582
method.__name__ = name
6683
method.__doc__ = attr.__doc__
6784
return method
6885

6986

70-
def inherit_names(names: List[str], delegate, cache: bool = False):
87+
def inherit_names(names: List[str], delegate, cache: bool = False, wrap: bool = False):
7188
"""
7289
Class decorator to pin attributes from an ExtensionArray to a Index subclass.
7390
@@ -76,11 +93,13 @@ def inherit_names(names: List[str], delegate, cache: bool = False):
7693
names : List[str]
7794
delegate : class
7895
cache : bool, default False
96+
wrap : bool, default False
97+
Whether to wrap the inherited result in an Index.
7998
"""
8099

81100
def wrapper(cls):
82101
for name in names:
83-
meth = inherit_from_data(name, delegate, cache=cache)
102+
meth = inherit_from_data(name, delegate, cache=cache, wrap=wrap)
84103
setattr(cls, name, meth)
85104

86105
return cls

pandas/core/indexes/interval.py

+12-34
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
)
3737
from pandas.core.dtypes.missing import isna
3838

39-
from pandas.core import accessor
4039
from pandas.core.algorithms import take_1d
4140
from pandas.core.arrays.interval import IntervalArray, _interval_shared_docs
4241
import pandas.core.common as com
@@ -186,31 +185,27 @@ def func(intvidx_self, other, sort=False):
186185
),
187186
)
188187
)
189-
@accessor.delegate_names(
190-
delegate=IntervalArray,
191-
accessors=["length", "size", "left", "right", "mid", "closed", "dtype"],
192-
typ="property",
193-
overwrite=True,
194-
)
195-
@accessor.delegate_names(
196-
delegate=IntervalArray,
197-
accessors=[
188+
@inherit_names(["set_closed", "to_tuples"], IntervalArray, wrap=True)
189+
@inherit_names(
190+
[
191+
"__len__",
198192
"__array__",
199193
"overlaps",
200194
"contains",
201-
"__len__",
202-
"set_closed",
203-
"to_tuples",
195+
"size",
196+
"dtype",
197+
"left",
198+
"right",
199+
"length",
204200
],
205-
typ="method",
206-
overwrite=True,
201+
IntervalArray,
207202
)
208203
@inherit_names(
209-
["is_non_overlapping_monotonic", "mid", "_ndarray_values"],
204+
["is_non_overlapping_monotonic", "mid", "_ndarray_values", "closed"],
210205
IntervalArray,
211206
cache=True,
212207
)
213-
class IntervalIndex(IntervalMixin, ExtensionIndex, accessor.PandasDelegate):
208+
class IntervalIndex(IntervalMixin, ExtensionIndex):
214209
_typ = "intervalindex"
215210
_comparables = ["name"]
216211
_attributes = ["name", "closed"]
@@ -221,8 +216,6 @@ class IntervalIndex(IntervalMixin, ExtensionIndex, accessor.PandasDelegate):
221216
# Immutable, so we are able to cache computations like isna in '_mask'
222217
_mask = None
223218

224-
_raw_inherit = {"__array__", "overlaps", "contains"}
225-
226219
# --------------------------------------------------------------------
227220
# Constructors
228221

@@ -1155,21 +1148,6 @@ def is_all_dates(self) -> bool:
11551148

11561149
# TODO: arithmetic operations
11571150

1158-
def _delegate_property_get(self, name, *args, **kwargs):
1159-
""" method delegation to the ._values """
1160-
prop = getattr(self._data, name)
1161-
return prop # no wrapping for now
1162-
1163-
def _delegate_method(self, name, *args, **kwargs):
1164-
""" method delegation to the ._data """
1165-
method = getattr(self._data, name)
1166-
res = method(*args, **kwargs)
1167-
if is_scalar(res) or name in self._raw_inherit:
1168-
return res
1169-
if isinstance(res, IntervalArray):
1170-
return type(self)._simple_new(res, name=self.name)
1171-
return Index(res)
1172-
11731151
# GH#30817 until IntervalArray implements inequalities, get them from Index
11741152
def __lt__(self, other):
11751153
return Index.__lt__(self, other)

pandas/core/indexes/timedeltas.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,12 @@ class TimedeltaDelegateMixin(DatetimelikeDelegateMixin):
4545
_raw_methods = {"to_pytimedelta", "sum", "std", "median", "_format_native_types"}
4646

4747
_delegated_properties = TimedeltaArray._datetimelike_ops + list(_raw_properties)
48-
_delegated_methods = (
49-
TimedeltaArray._datetimelike_methods
50-
+ list(_raw_methods)
51-
+ ["_box_values", "__neg__", "__pos__", "__abs__"]
52-
)
48+
_delegated_methods = TimedeltaArray._datetimelike_methods + list(_raw_methods)
5349

5450

51+
@inherit_names(
52+
["_box_values", "__neg__", "__pos__", "__abs__"], TimedeltaArray, wrap=True
53+
)
5554
@inherit_names(
5655
[
5756
"_bool_ops",

0 commit comments

Comments
 (0)