3737from pandas .core .dtypes .generic import ABCSeries
3838from pandas .core .dtypes .missing import isna
3939
40+ from pandas .core import accessor
4041from pandas .core .algorithms import take_1d
4142from pandas .core .arrays .interval import IntervalArray , _interval_shared_docs
4243import pandas .core .common as com
@@ -181,7 +182,28 @@ def func(intvidx_self, other, sort=False):
181182 ),
182183 )
183184)
184- class IntervalIndex (IntervalMixin , Index ):
185+ @accessor .delegate_names (
186+ delegate = IntervalArray ,
187+ accessors = [
188+ "_ndarray_values" ,
189+ "length" ,
190+ "size" ,
191+ "left" ,
192+ "right" ,
193+ "mid" ,
194+ "closed" ,
195+ "dtype" ,
196+ ],
197+ typ = "property" ,
198+ overwrite = True ,
199+ )
200+ @accessor .delegate_names (
201+ delegate = IntervalArray ,
202+ accessors = ["__array__" , "overlaps" , "contains" ],
203+ typ = "method" ,
204+ overwrite = True ,
205+ )
206+ class IntervalIndex (IntervalMixin , Index , accessor .PandasDelegate ):
185207 _typ = "intervalindex"
186208 _comparables = ["name" ]
187209 _attributes = ["name" , "closed" ]
@@ -192,6 +214,8 @@ class IntervalIndex(IntervalMixin, Index):
192214 # Immutable, so we are able to cache computations like isna in '_mask'
193215 _mask = None
194216
217+ _raw_inherit = {"_ndarray_values" , "__array__" , "overlaps" , "contains" }
218+
195219 # --------------------------------------------------------------------
196220 # Constructors
197221
@@ -388,30 +412,6 @@ def to_tuples(self, na_tuple=True):
388412 def _multiindex (self ):
389413 return MultiIndex .from_arrays ([self .left , self .right ], names = ["left" , "right" ])
390414
391- @property
392- def left (self ):
393- """
394- Return the left endpoints of each Interval in the IntervalIndex as
395- an Index.
396- """
397- return self ._data ._left
398-
399- @property
400- def right (self ):
401- """
402- Return the right endpoints of each Interval in the IntervalIndex as
403- an Index.
404- """
405- return self ._data ._right
406-
407- @property
408- def closed (self ):
409- """
410- Whether the intervals are closed on the left-side, right-side, both or
411- neither.
412- """
413- return self ._data ._closed
414-
415415 @Appender (
416416 _interval_shared_docs ["set_closed" ]
417417 % dict (
@@ -434,25 +434,8 @@ def closed(self):
434434 )
435435 )
436436 def set_closed (self , closed ):
437- if closed not in _VALID_CLOSED :
438- raise ValueError (f"invalid option for 'closed': { closed } " )
439-
440- # return self._shallow_copy(closed=closed)
441437 array = self ._data .set_closed (closed )
442- return self ._simple_new (array , self .name )
443-
444- @property
445- def length (self ):
446- """
447- Return an Index with entries denoting the length of each Interval in
448- the IntervalIndex.
449- """
450- return self ._data .length
451-
452- @property
453- def size (self ):
454- # Avoid materializing ndarray[Interval]
455- return self ._data .size
438+ return self ._simple_new (array , self .name ) # TODO: can we use _shallow_copy?
456439
457440 def __len__ (self ) -> int :
458441 return len (self .left )
@@ -468,16 +451,6 @@ def values(self):
468451 def _values (self ):
469452 return self ._data
470453
471- @cache_readonly
472- def _ndarray_values (self ) -> np .ndarray :
473- return np .array (self ._data )
474-
475- def __array__ (self , result = None ):
476- """
477- The array interface, return my values.
478- """
479- return self ._ndarray_values
480-
481454 def __array_wrap__ (self , result , context = None ):
482455 # we don't want the superclass implementation
483456 return result
@@ -506,13 +479,6 @@ def astype(self, dtype, copy=True):
506479 return self ._shallow_copy (new_values .left , new_values .right )
507480 return super ().astype (dtype , copy = copy )
508481
509- @cache_readonly
510- def dtype (self ):
511- """
512- Return the dtype object of the underlying data.
513- """
514- return self ._data .dtype
515-
516482 @property
517483 def inferred_type (self ) -> str :
518484 """Return a string of the type inferred from the values"""
@@ -1177,44 +1143,6 @@ def equals(self, other) -> bool:
11771143 and self .closed == other .closed
11781144 )
11791145
1180- @Appender (
1181- _interval_shared_docs ["contains" ]
1182- % dict (
1183- klass = "IntervalIndex" ,
1184- examples = textwrap .dedent (
1185- """\
1186- >>> intervals = pd.IntervalIndex.from_tuples([(0, 1), (1, 3), (2, 4)])
1187- >>> intervals
1188- IntervalIndex([(0, 1], (1, 3], (2, 4]],
1189- closed='right',
1190- dtype='interval[int64]')
1191- >>> intervals.contains(0.5)
1192- array([ True, False, False])
1193- """
1194- ),
1195- )
1196- )
1197- def contains (self , other ):
1198- return self ._data .contains (other )
1199-
1200- @Appender (
1201- _interval_shared_docs ["overlaps" ]
1202- % dict (
1203- klass = "IntervalIndex" ,
1204- examples = textwrap .dedent (
1205- """\
1206- >>> intervals = pd.IntervalIndex.from_tuples([(0, 1), (1, 3), (2, 4)])
1207- >>> intervals
1208- IntervalIndex([(0, 1], (1, 3], (2, 4]],
1209- closed='right',
1210- dtype='interval[int64]')
1211- """
1212- ),
1213- )
1214- )
1215- def overlaps (self , other ):
1216- return self ._data .overlaps (other )
1217-
12181146 @Appender (_index_shared_docs ["intersection" ])
12191147 @SetopCheck (op_name = "intersection" )
12201148 def intersection (
@@ -1314,6 +1242,19 @@ def is_all_dates(self) -> bool:
13141242
13151243 # TODO: arithmetic operations
13161244
1245+ def _delegate_property_get (self , name , * args , ** kwargs ):
1246+ """ method delegation to the ._values """
1247+ prop = getattr (self ._data , name )
1248+ return prop # no wrapping for now
1249+
1250+ def _delegate_method (self , name , * args , ** kwargs ):
1251+ """ method delegation to the ._data """
1252+ method = getattr (self ._data , name )
1253+ res = method (* args , ** kwargs )
1254+ if is_scalar (res ) or name in self ._raw_inherit :
1255+ return res
1256+ return type (self )(res , name = self .name )
1257+
13171258
13181259IntervalIndex ._add_logical_methods_disabled ()
13191260
0 commit comments