diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 64ba18271100e..928c4928dded0 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -5345,6 +5345,16 @@ def _get_indexer_non_comparable( """ if method is not None: other = unpack_nested_dtype(target) + if self._is_multi ^ other._is_multi: + kind = other.dtype.type if self._is_multi else self.dtype.type + raise TypeError( + f"'<' not supported between instances of {kind} and 'tuple'" + ) + elif self._is_multi and other._is_multi: + assert self.nlevels != other.nlevels + # Python allows comparison between tuples of different lengths, + # but for our purposes such a comparison is not meaningful. + raise TypeError("'<' not supported between tuples of different lengths") raise TypeError(f"Cannot compare dtypes {self.dtype} and {other.dtype}") no_matches = -1 * np.ones(target.shape, dtype=np.intp) @@ -5474,6 +5484,14 @@ def _should_compare(self, other: Index) -> bool: other = unpack_nested_dtype(other) dtype = other.dtype + if other._is_multi: + if not self._is_multi: + # other contains only tuples so unless we are object-dtype, + # there can never be any matches + return self._is_comparable_dtype(dtype) + return self.nlevels == other.nlevels + # TODO: we can get more specific requiring levels are comparable? + return self._is_comparable_dtype(dtype) or is_object_dtype(dtype) def _is_comparable_dtype(self, dtype: DtypeObj) -> bool: diff --git a/pandas/tests/indexes/multi/test_indexing.py b/pandas/tests/indexes/multi/test_indexing.py index 9e1097ce5951f..ec7ddf8b4d67a 100644 --- a/pandas/tests/indexes/multi/test_indexing.py +++ b/pandas/tests/indexes/multi/test_indexing.py @@ -457,6 +457,15 @@ def test_get_indexer_kwarg_validation(self): with pytest.raises(ValueError, match=msg): mi.get_indexer(mi[:-1], tolerance="piano") + def test_get_indexer_mismatched_nlevels(self): + mi = MultiIndex.from_product([range(3), ["A", "B"]]) + + other = MultiIndex.from_product([range(3), ["A", "B"], range(2)]) + + msg = "tuples of different lengths" + with pytest.raises(TypeError, match=msg): + mi.get_indexer(other, method="pad") + def test_getitem(idx): # scalar