Skip to content

Commit 687e756

Browse files
authored
REF: de-duplicate IntervalIndex compatiblity checks (#37916)
1 parent 8c4ef78 commit 687e756

File tree

3 files changed

+25
-25
lines changed

3 files changed

+25
-25
lines changed

pandas/_libs/interval.pyx

+2-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ cdef class IntervalMixin:
179179
return (self.right == self.left) & (self.closed != 'both')
180180

181181
def _check_closed_matches(self, other, name='other'):
182-
"""Check if the closed attribute of `other` matches.
182+
"""
183+
Check if the closed attribute of `other` matches.
183184
184185
Note that 'left' and 'right' are considered different from 'both'.
185186

pandas/core/indexes/interval.py

+19-20
Original file line numberDiff line numberDiff line change
@@ -130,19 +130,13 @@ def wrapped(self, other, sort=False):
130130
if op_name in ("difference",):
131131
result = result.astype(self.dtype)
132132
return result
133-
elif self.closed != other.closed:
134-
raise ValueError(
135-
"can only do set operations between two IntervalIndex "
136-
"objects that are closed on the same side"
137-
)
138133

139-
# GH 19016: ensure set op will not return a prohibited dtype
140-
subtypes = [self.dtype.subtype, other.dtype.subtype]
141-
common_subtype = find_common_type(subtypes)
142-
if is_object_dtype(common_subtype):
134+
if self._is_non_comparable_own_type(other):
135+
# GH#19016: ensure set op will not return a prohibited dtype
143136
raise TypeError(
144-
f"can only do {op_name} between two IntervalIndex "
145-
"objects that have compatible dtypes"
137+
"can only do set operations between two IntervalIndex "
138+
"objects that are closed on the same side "
139+
"and have compatible dtypes"
146140
)
147141

148142
return method(self, other, sort)
@@ -717,11 +711,8 @@ def get_indexer(
717711
if self.equals(target_as_index):
718712
return np.arange(len(self), dtype="intp")
719713

720-
# different closed or incompatible subtype -> no matches
721-
common_subtype = find_common_type(
722-
[self.dtype.subtype, target_as_index.dtype.subtype]
723-
)
724-
if self.closed != target_as_index.closed or is_object_dtype(common_subtype):
714+
if self._is_non_comparable_own_type(target_as_index):
715+
# different closed or incompatible subtype -> no matches
725716
return np.repeat(np.intp(-1), len(target_as_index))
726717

727718
# non-overlapping -> at most one match per interval in target_as_index
@@ -763,10 +754,8 @@ def get_indexer_non_unique(
763754

764755
# check that target_as_index IntervalIndex is compatible
765756
if isinstance(target_as_index, IntervalIndex):
766-
common_subtype = find_common_type(
767-
[self.dtype.subtype, target_as_index.dtype.subtype]
768-
)
769-
if self.closed != target_as_index.closed or is_object_dtype(common_subtype):
757+
758+
if self._is_non_comparable_own_type(target_as_index):
770759
# different closed or incompatible subtype -> no matches
771760
return (
772761
np.repeat(-1, len(target_as_index)),
@@ -837,6 +826,16 @@ def _convert_list_indexer(self, keyarr):
837826

838827
return locs
839828

829+
def _is_non_comparable_own_type(self, other: "IntervalIndex") -> bool:
830+
# different closed or incompatible subtype -> no matches
831+
832+
# TODO: once closed is part of IntervalDtype, we can just define
833+
# is_comparable_dtype GH#19371
834+
if self.closed != other.closed:
835+
return True
836+
common_subtype = find_common_type([self.dtype.subtype, other.dtype.subtype])
837+
return is_object_dtype(common_subtype)
838+
840839
# --------------------------------------------------------------------
841840

842841
@cache_readonly

pandas/tests/indexes/interval/test_setops.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -159,18 +159,18 @@ def test_set_incompatible_types(self, closed, op_name, sort):
159159
# mixed closed
160160
msg = (
161161
"can only do set operations between two IntervalIndex objects "
162-
"that are closed on the same side"
162+
"that are closed on the same side and have compatible dtypes"
163163
)
164164
for other_closed in {"right", "left", "both", "neither"} - {closed}:
165165
other = monotonic_index(0, 11, closed=other_closed)
166-
with pytest.raises(ValueError, match=msg):
166+
with pytest.raises(TypeError, match=msg):
167167
set_op(other, sort=sort)
168168

169169
# GH 19016: incompatible dtypes
170170
other = interval_range(Timestamp("20180101"), periods=9, closed=closed)
171171
msg = (
172-
f"can only do {op_name} between two IntervalIndex objects that have "
173-
"compatible dtypes"
172+
"can only do set operations between two IntervalIndex objects "
173+
"that are closed on the same side and have compatible dtypes"
174174
)
175175
with pytest.raises(TypeError, match=msg):
176176
set_op(other, sort=sort)

0 commit comments

Comments
 (0)