diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index 436a7dd062c4a..028472ad93e52 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -640,17 +640,10 @@ def fillna(self, value=None, method=None, limit=None): if limit is not None: raise TypeError("limit is not supported for IntervalArray.") - if not isinstance(value, Interval): - msg = ( - "'IntervalArray.fillna' only supports filling with a " - f"scalar 'pandas.Interval'. Got a '{type(value).__name__}' instead." - ) - raise TypeError(msg) - - self._check_closed_matches(value, name="value") + value_left, value_right = self._validate_fillna_value(value) - left = self.left.fillna(value=value.left) - right = self.right.fillna(value=value.right) + left = self.left.fillna(value=value_left) + right = self.right.fillna(value=value_right) return self._shallow_copy(left, right) @property @@ -845,18 +838,7 @@ def take(self, indices, allow_fill=False, fill_value=None, axis=None, **kwargs): fill_left = fill_right = fill_value if allow_fill: - if fill_value is None: - fill_left = fill_right = self.left._na_value - elif is_interval(fill_value): - self._check_closed_matches(fill_value, name="fill_value") - fill_left, fill_right = fill_value.left, fill_value.right - elif not is_scalar(fill_value) and notna(fill_value): - msg = ( - "'IntervalArray.fillna' only supports filling with a " - "'scalar pandas.Interval or NA'. " - f"Got a '{type(fill_value).__name__}' instead." - ) - raise ValueError(msg) + fill_left, fill_right = self._validate_fill_value(fill_value) left_take = take( 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): return self._shallow_copy(left_take, right_take) + def _validate_fill_value(self, value): + if is_interval(value): + self._check_closed_matches(value, name="fill_value") + fill_left, fill_right = value.left, value.right + elif not is_scalar(value) and notna(value): + msg = ( + "'IntervalArray.fillna' only supports filling with a " + "'scalar pandas.Interval or NA'. " + f"Got a '{type(value).__name__}' instead." + ) + raise ValueError(msg) + else: + fill_left = fill_right = self.left._na_value + return fill_left, fill_right + + def _validate_fillna_value(self, value): + if not isinstance(value, Interval): + msg = ( + "'IntervalArray.fillna' only supports filling with a " + f"scalar 'pandas.Interval'. Got a '{type(value).__name__}' instead." + ) + raise TypeError(msg) + + self._check_closed_matches(value, name="value") + return value.left, value.right + + def _validate_insert_value(self, value): + if isinstance(value, Interval): + if value.closed != self.closed: + raise ValueError( + "inserted item must be closed on the same side as the index" + ) + left_insert = value.left + right_insert = value.right + elif is_scalar(value) and isna(value): + # GH#18295 + left_insert = right_insert = value + else: + raise ValueError( + "can only insert Interval objects and NA into an IntervalIndex" + ) + return left_insert, right_insert + def value_counts(self, dropna=True): """ Returns a Series containing counts of each interval. diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py index ad0a7ea32a1cc..9ef584f5b7fbc 100644 --- a/pandas/core/indexes/interval.py +++ b/pandas/core/indexes/interval.py @@ -333,7 +333,9 @@ def from_tuples( # -------------------------------------------------------------------- @Appender(Index._shallow_copy.__doc__) - def _shallow_copy(self, values=None, name: Label = lib.no_default): + def _shallow_copy( + self, values: Optional[IntervalArray] = None, name: Label = lib.no_default + ): name = self.name if name is lib.no_default else name cache = self._cache.copy() if values is None else {} if values is None: @@ -927,20 +929,7 @@ def insert(self, loc, item): ------- IntervalIndex """ - if isinstance(item, Interval): - if item.closed != self.closed: - raise ValueError( - "inserted item must be closed on the same side as the index" - ) - left_insert = item.left - right_insert = item.right - elif is_scalar(item) and isna(item): - # GH 18295 - left_insert = right_insert = item - else: - raise ValueError( - "can only insert Interval objects and NA into an IntervalIndex" - ) + left_insert, right_insert = self._data._validate_insert_value(item) new_left = self.left.insert(loc, left_insert) new_right = self.right.insert(loc, right_insert)