Skip to content

Commit fa9d66c

Browse files
authored
REF: move MultiIndex._get_indexer casting to _maybe_promote (#42109)
1 parent d7c2a84 commit fa9d66c

File tree

2 files changed

+19
-34
lines changed

2 files changed

+19
-34
lines changed

pandas/core/indexes/base.py

+19-3
Original file line numberDiff line numberDiff line change
@@ -3394,6 +3394,9 @@ def get_indexer(
33943394
if not self._index_as_unique:
33953395
raise InvalidIndexError(self._requires_unique_msg)
33963396

3397+
if len(target) == 0:
3398+
return np.array([], dtype=np.intp)
3399+
33973400
if not self._should_compare(target) and not is_interval_dtype(self.dtype):
33983401
# IntervalIndex get special treatment bc numeric scalars can be
33993402
# matched to Interval scalars
@@ -3402,9 +3405,14 @@ def get_indexer(
34023405
if is_categorical_dtype(target.dtype):
34033406
# potential fastpath
34043407
# get an indexer for unique categories then propagate to codes via take_nd
3405-
# Note: calling get_indexer instead of _get_indexer causes
3406-
# RecursionError GH#42088
3407-
categories_indexer = self._get_indexer(target.categories)
3408+
if is_categorical_dtype(self.dtype):
3409+
# Avoid RecursionError GH#42088
3410+
categories_indexer = self._get_indexer(target.categories)
3411+
else:
3412+
# get_indexer instead of _get_indexer needed for MultiIndex cases
3413+
# e.g. test_append_different_columns_types
3414+
categories_indexer = self.get_indexer(target.categories)
3415+
34083416
indexer = algos.take_nd(categories_indexer, target.codes, fill_value=-1)
34093417

34103418
if (not self._is_multi and self.hasnans) and target.hasnans:
@@ -5341,6 +5349,14 @@ def _maybe_promote(self, other: Index) -> tuple[Index, Index]:
53415349
# TODO: may need itemsize check if we have non-64-bit Indexes
53425350
return self, other.astype(self.dtype)
53435351

5352+
elif self._is_multi and not other._is_multi:
5353+
try:
5354+
# "Type[Index]" has no attribute "from_tuples"
5355+
other = type(self).from_tuples(other) # type: ignore[attr-defined]
5356+
except (TypeError, ValueError):
5357+
# let's instead try with a straight Index
5358+
self = Index(self._values)
5359+
53445360
if not is_object_dtype(self.dtype) and is_object_dtype(other.dtype):
53455361
# Reverse op so we dont need to re-implement on the subclasses
53465362
other, self = other._maybe_promote(self)

pandas/core/indexes/multi.py

-31
Original file line numberDiff line numberDiff line change
@@ -2644,37 +2644,6 @@ def _get_partial_string_timestamp_match_key(self, key):
26442644

26452645
return key
26462646

2647-
def _get_indexer(
2648-
self,
2649-
target: Index,
2650-
method: str | None = None,
2651-
limit: int | None = None,
2652-
tolerance=None,
2653-
) -> np.ndarray:
2654-
# returned ndarray is np.intp
2655-
2656-
# empty indexer
2657-
if not len(target):
2658-
return ensure_platform_int(np.array([]))
2659-
2660-
if not isinstance(target, MultiIndex):
2661-
try:
2662-
target = MultiIndex.from_tuples(target)
2663-
except (TypeError, ValueError):
2664-
2665-
# let's instead try with a straight Index
2666-
if method is None:
2667-
return Index(self._values).get_indexer(
2668-
target, method=method, limit=limit, tolerance=tolerance
2669-
)
2670-
2671-
# TODO: explicitly raise here? we only have one test that
2672-
# gets here, and it is checking that we raise with method="nearest"
2673-
2674-
# Note: we only get here (in extant tests at least) with
2675-
# target.nlevels == self.nlevels
2676-
return super()._get_indexer(target, method, limit, tolerance)
2677-
26782647
def get_slice_bound(
26792648
self, label: Hashable | Sequence[Hashable], side: str, kind: str | None = None
26802649
) -> int:

0 commit comments

Comments
 (0)