Skip to content

Commit cd26fe2

Browse files
authored
REF: _validate_foo pattern for IntervalArray (#36414)
1 parent be6908e commit cd26fe2

File tree

2 files changed

+51
-37
lines changed

2 files changed

+51
-37
lines changed

pandas/core/arrays/interval.py

+47-22
Original file line numberDiff line numberDiff line change
@@ -640,17 +640,10 @@ def fillna(self, value=None, method=None, limit=None):
640640
if limit is not None:
641641
raise TypeError("limit is not supported for IntervalArray.")
642642

643-
if not isinstance(value, Interval):
644-
msg = (
645-
"'IntervalArray.fillna' only supports filling with a "
646-
f"scalar 'pandas.Interval'. Got a '{type(value).__name__}' instead."
647-
)
648-
raise TypeError(msg)
649-
650-
self._check_closed_matches(value, name="value")
643+
value_left, value_right = self._validate_fillna_value(value)
651644

652-
left = self.left.fillna(value=value.left)
653-
right = self.right.fillna(value=value.right)
645+
left = self.left.fillna(value=value_left)
646+
right = self.right.fillna(value=value_right)
654647
return self._shallow_copy(left, right)
655648

656649
@property
@@ -845,18 +838,7 @@ def take(self, indices, allow_fill=False, fill_value=None, axis=None, **kwargs):
845838

846839
fill_left = fill_right = fill_value
847840
if allow_fill:
848-
if fill_value is None:
849-
fill_left = fill_right = self.left._na_value
850-
elif is_interval(fill_value):
851-
self._check_closed_matches(fill_value, name="fill_value")
852-
fill_left, fill_right = fill_value.left, fill_value.right
853-
elif not is_scalar(fill_value) and notna(fill_value):
854-
msg = (
855-
"'IntervalArray.fillna' only supports filling with a "
856-
"'scalar pandas.Interval or NA'. "
857-
f"Got a '{type(fill_value).__name__}' instead."
858-
)
859-
raise ValueError(msg)
841+
fill_left, fill_right = self._validate_fill_value(fill_value)
860842

861843
left_take = take(
862844
self.left, indices, allow_fill=allow_fill, fill_value=fill_left
@@ -867,6 +849,49 @@ def take(self, indices, allow_fill=False, fill_value=None, axis=None, **kwargs):
867849

868850
return self._shallow_copy(left_take, right_take)
869851

852+
def _validate_fill_value(self, value):
853+
if is_interval(value):
854+
self._check_closed_matches(value, name="fill_value")
855+
fill_left, fill_right = value.left, value.right
856+
elif not is_scalar(value) and notna(value):
857+
msg = (
858+
"'IntervalArray.fillna' only supports filling with a "
859+
"'scalar pandas.Interval or NA'. "
860+
f"Got a '{type(value).__name__}' instead."
861+
)
862+
raise ValueError(msg)
863+
else:
864+
fill_left = fill_right = self.left._na_value
865+
return fill_left, fill_right
866+
867+
def _validate_fillna_value(self, value):
868+
if not isinstance(value, Interval):
869+
msg = (
870+
"'IntervalArray.fillna' only supports filling with a "
871+
f"scalar 'pandas.Interval'. Got a '{type(value).__name__}' instead."
872+
)
873+
raise TypeError(msg)
874+
875+
self._check_closed_matches(value, name="value")
876+
return value.left, value.right
877+
878+
def _validate_insert_value(self, value):
879+
if isinstance(value, Interval):
880+
if value.closed != self.closed:
881+
raise ValueError(
882+
"inserted item must be closed on the same side as the index"
883+
)
884+
left_insert = value.left
885+
right_insert = value.right
886+
elif is_scalar(value) and isna(value):
887+
# GH#18295
888+
left_insert = right_insert = value
889+
else:
890+
raise ValueError(
891+
"can only insert Interval objects and NA into an IntervalIndex"
892+
)
893+
return left_insert, right_insert
894+
870895
def value_counts(self, dropna=True):
871896
"""
872897
Returns a Series containing counts of each interval.

pandas/core/indexes/interval.py

+4-15
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,9 @@ def from_tuples(
333333
# --------------------------------------------------------------------
334334

335335
@Appender(Index._shallow_copy.__doc__)
336-
def _shallow_copy(self, values=None, name: Label = lib.no_default):
336+
def _shallow_copy(
337+
self, values: Optional[IntervalArray] = None, name: Label = lib.no_default
338+
):
337339
name = self.name if name is lib.no_default else name
338340
cache = self._cache.copy() if values is None else {}
339341
if values is None:
@@ -927,20 +929,7 @@ def insert(self, loc, item):
927929
-------
928930
IntervalIndex
929931
"""
930-
if isinstance(item, Interval):
931-
if item.closed != self.closed:
932-
raise ValueError(
933-
"inserted item must be closed on the same side as the index"
934-
)
935-
left_insert = item.left
936-
right_insert = item.right
937-
elif is_scalar(item) and isna(item):
938-
# GH 18295
939-
left_insert = right_insert = item
940-
else:
941-
raise ValueError(
942-
"can only insert Interval objects and NA into an IntervalIndex"
943-
)
932+
left_insert, right_insert = self._data._validate_insert_value(item)
944933

945934
new_left = self.left.insert(loc, left_insert)
946935
new_right = self.right.insert(loc, right_insert)

0 commit comments

Comments
 (0)