Skip to content

Commit c608824

Browse files
authored
REF: remove need to override get_indexer_non_unique in DatetimeIndexOpsMixin (#33792)
1 parent 0163b79 commit c608824

File tree

5 files changed

+30
-37
lines changed

5 files changed

+30
-37
lines changed

pandas/_libs/index.pyx

+4
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,10 @@ cdef class DatetimeEngine(Int64Engine):
441441
except KeyError:
442442
raise KeyError(val)
443443

444+
def get_indexer_non_unique(self, targets):
445+
# we may get datetime64[ns] or timedelta64[ns], cast these to int64
446+
return super().get_indexer_non_unique(targets.view("i8"))
447+
444448
def get_indexer(self, values):
445449
self._ensure_mapping_populated()
446450
if values.dtype != self._get_box_dtype():

pandas/core/indexes/base.py

+24-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from pandas._libs.tslibs import OutOfBoundsDatetime, Timestamp
1414
from pandas._libs.tslibs.period import IncompatibleFrequency
1515
from pandas._libs.tslibs.timezones import tz_compare
16-
from pandas._typing import Label
16+
from pandas._typing import DtypeObj, Label
1717
from pandas.compat import set_function_name
1818
from pandas.compat.numpy import function as nv
1919
from pandas.util._decorators import Appender, Substitution, cache_readonly, doc
@@ -4626,6 +4626,10 @@ def get_indexer_non_unique(self, target):
46264626
if pself is not self or ptarget is not target:
46274627
return pself.get_indexer_non_unique(ptarget)
46284628

4629+
if not self._is_comparable_dtype(target.dtype):
4630+
no_matches = -1 * np.ones(self.shape, dtype=np.intp)
4631+
return no_matches, no_matches
4632+
46294633
if is_categorical_dtype(target.dtype):
46304634
tgt_values = np.asarray(target)
46314635
else:
@@ -4651,16 +4655,33 @@ def get_indexer_for(self, target, **kwargs):
46514655
indexer, _ = self.get_indexer_non_unique(target, **kwargs)
46524656
return indexer
46534657

4654-
def _maybe_promote(self, other):
4655-
# A hack, but it works
4658+
def _maybe_promote(self, other: "Index"):
4659+
"""
4660+
When dealing with an object-dtype Index and a non-object Index, see
4661+
if we can upcast the object-dtype one to improve performance.
4662+
"""
46564663

46574664
if self.inferred_type == "date" and isinstance(other, ABCDatetimeIndex):
46584665
return type(other)(self), other
4666+
elif self.inferred_type == "timedelta" and isinstance(other, ABCTimedeltaIndex):
4667+
# TODO: we dont have tests that get here
4668+
return type(other)(self), other
46594669
elif self.inferred_type == "boolean":
46604670
if not is_object_dtype(self.dtype):
46614671
return self.astype("object"), other.astype("object")
4672+
4673+
if not is_object_dtype(self.dtype) and is_object_dtype(other.dtype):
4674+
# Reverse op so we dont need to re-implement on the subclasses
4675+
other, self = other._maybe_promote(self)
4676+
46624677
return self, other
46634678

4679+
def _is_comparable_dtype(self, dtype: DtypeObj) -> bool:
4680+
"""
4681+
Can we compare values of the given dtype to our own?
4682+
"""
4683+
return True
4684+
46644685
def groupby(self, values) -> PrettyDict[Hashable, np.ndarray]:
46654686
"""
46664687
Group the index labels by a given array of values.

pandas/core/indexes/datetimelike.py

+2-24
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@
88

99
from pandas._libs import NaT, iNaT, join as libjoin, lib
1010
from pandas._libs.tslibs import timezones
11-
from pandas._typing import DtypeObj, Label
11+
from pandas._typing import Label
1212
from pandas.compat.numpy import function as nv
1313
from pandas.errors import AbstractMethodError
1414
from pandas.util._decorators import Appender, cache_readonly, doc
1515

1616
from pandas.core.dtypes.common import (
1717
ensure_int64,
18-
ensure_platform_int,
1918
is_bool_dtype,
2019
is_datetime64_any_dtype,
2120
is_dtype_equal,
@@ -35,7 +34,7 @@
3534
from pandas.core.arrays.datetimelike import DatetimeLikeArrayMixin
3635
from pandas.core.base import IndexOpsMixin
3736
import pandas.core.indexes.base as ibase
38-
from pandas.core.indexes.base import Index, _index_shared_docs, ensure_index
37+
from pandas.core.indexes.base import Index, _index_shared_docs
3938
from pandas.core.indexes.extension import (
4039
ExtensionIndex,
4140
inherit_names,
@@ -124,12 +123,6 @@ class DatetimeIndexOpsMixin(ExtensionIndex):
124123
def is_all_dates(self) -> bool:
125124
return True
126125

127-
def _is_comparable_dtype(self, dtype: DtypeObj) -> bool:
128-
"""
129-
Can we compare values of the given dtype to our own?
130-
"""
131-
raise AbstractMethodError(self)
132-
133126
# ------------------------------------------------------------------------
134127
# Abstract data attributes
135128

@@ -455,21 +448,6 @@ def _partial_date_slice(
455448
# try to find the dates
456449
return (lhs_mask & rhs_mask).nonzero()[0]
457450

458-
@Appender(Index.get_indexer_non_unique.__doc__)
459-
def get_indexer_non_unique(self, target):
460-
target = ensure_index(target)
461-
pself, ptarget = self._maybe_promote(target)
462-
if pself is not self or ptarget is not target:
463-
return pself.get_indexer_non_unique(ptarget)
464-
465-
if not self._is_comparable_dtype(target.dtype):
466-
no_matches = -1 * np.ones(self.shape, dtype=np.intp)
467-
return no_matches, no_matches
468-
469-
tgt_values = target.asi8
470-
indexer, missing = self._engine.get_indexer_non_unique(tgt_values)
471-
return ensure_platform_int(indexer), missing
472-
473451
# --------------------------------------------------------------------
474452
# Arithmetic Methods
475453

pandas/core/indexes/datetimes.py

-5
Original file line numberDiff line numberDiff line change
@@ -538,11 +538,6 @@ def _validate_partial_date_slice(self, reso: str):
538538
# _parsed_string_to_bounds allows it.
539539
raise KeyError
540540

541-
def _maybe_promote(self, other):
542-
if other.inferred_type == "date":
543-
other = DatetimeIndex(other)
544-
return self, other
545-
546541
def get_loc(self, key, method=None, tolerance=None):
547542
"""
548543
Get integer location for requested label

pandas/core/indexes/timedeltas.py

-5
Original file line numberDiff line numberDiff line change
@@ -197,11 +197,6 @@ def astype(self, dtype, copy=True):
197197
return Index(result.astype("i8"), name=self.name)
198198
return DatetimeIndexOpsMixin.astype(self, dtype, copy=copy)
199199

200-
def _maybe_promote(self, other):
201-
if other.inferred_type == "timedelta":
202-
other = TimedeltaIndex(other)
203-
return self, other
204-
205200
def _is_comparable_dtype(self, dtype: DtypeObj) -> bool:
206201
"""
207202
Can we compare values of the given dtype to our own?

0 commit comments

Comments
 (0)