Skip to content

Commit 07eda6a

Browse files
authored
REF: do all convert_tolerance casting inside Index.get_loc (#31425)
1 parent 4808c16 commit 07eda6a

File tree

5 files changed

+23
-22
lines changed

5 files changed

+23
-22
lines changed

doc/source/whatsnew/v1.1.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ Indexing
150150
- Bug in :meth:`PeriodIndex.get_loc` treating higher-resolution strings differently from :meth:`PeriodIndex.get_value` (:issue:`31172`)
151151
- Bug in :meth:`Series.at` and :meth:`DataFrame.at` not matching ``.loc`` behavior when looking up an integer in a :class:`Float64Index` (:issue:`31329`)
152152
- Bug in :meth:`PeriodIndex.is_monotonic` incorrectly returning ``True`` when containing leading ``NaT`` entries (:issue:`31437`)
153+
- Bug in :meth:`DatetimeIndex.get_loc` raising ``KeyError`` with converted-integer key instead of the user-passed key (:issue:`31425`)
153154
-
154155

155156
Missing

pandas/core/indexes/base.py

+4
Original file line numberDiff line numberDiff line change
@@ -2884,6 +2884,10 @@ def get_loc(self, key, method=None, tolerance=None):
28842884
return self._engine.get_loc(key)
28852885
except KeyError:
28862886
return self._engine.get_loc(self._maybe_cast_indexer(key))
2887+
2888+
if tolerance is not None:
2889+
tolerance = self._convert_tolerance(tolerance, np.asarray(key))
2890+
28872891
indexer = self.get_indexer([key], method=method, tolerance=tolerance)
28882892
if indexer.ndim > 1 or indexer.size > 1:
28892893
raise TypeError("get_loc requires scalar valued input")

pandas/core/indexes/datetimes.py

+12-11
Original file line numberDiff line numberDiff line change
@@ -639,18 +639,13 @@ def get_loc(self, key, method=None, tolerance=None):
639639
if not is_scalar(key):
640640
raise InvalidIndexError(key)
641641

642+
orig_key = key
642643
if is_valid_nat_for_dtype(key, self.dtype):
643644
key = NaT
644645

645-
if tolerance is not None:
646-
# try converting tolerance now, so errors don't get swallowed by
647-
# the try/except clauses below
648-
tolerance = self._convert_tolerance(tolerance, np.asarray(key))
649-
650646
if isinstance(key, (datetime, np.datetime64)):
651647
# needed to localize naive datetimes
652648
key = self._maybe_cast_for_get_loc(key)
653-
return Index.get_loc(self, key, method, tolerance)
654649

655650
elif isinstance(key, str):
656651
try:
@@ -659,9 +654,8 @@ def get_loc(self, key, method=None, tolerance=None):
659654
pass
660655

661656
try:
662-
stamp = self._maybe_cast_for_get_loc(key)
663-
return Index.get_loc(self, stamp, method, tolerance)
664-
except (KeyError, ValueError):
657+
key = self._maybe_cast_for_get_loc(key)
658+
except ValueError:
665659
raise KeyError(key)
666660

667661
elif isinstance(key, timedelta):
@@ -670,14 +664,21 @@ def get_loc(self, key, method=None, tolerance=None):
670664
f"Cannot index {type(self).__name__} with {type(key).__name__}"
671665
)
672666

673-
if isinstance(key, time):
667+
elif isinstance(key, time):
674668
if method is not None:
675669
raise NotImplementedError(
676670
"cannot yet lookup inexact labels when key is a time object"
677671
)
678672
return self.indexer_at_time(key)
679673

680-
return Index.get_loc(self, key, method, tolerance)
674+
else:
675+
# unrecognized type
676+
raise KeyError(key)
677+
678+
try:
679+
return Index.get_loc(self, key, method, tolerance)
680+
except KeyError:
681+
raise KeyError(orig_key)
681682

682683
def _maybe_cast_for_get_loc(self, key) -> Timestamp:
683684
# needed to localize naive datetimes

pandas/core/indexes/timedeltas.py

-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
""" implement the TimedeltaIndex """
22

3-
import numpy as np
4-
53
from pandas._libs import NaT, Timedelta, index as libindex
64
from pandas.util._decorators import Appender
75

@@ -262,11 +260,6 @@ def get_loc(self, key, method=None, tolerance=None):
262260
else:
263261
raise KeyError(key)
264262

265-
if tolerance is not None:
266-
# try converting tolerance now, so errors don't get swallowed by
267-
# the try/except clauses below
268-
tolerance = self._convert_tolerance(tolerance, np.asarray(key))
269-
270263
return Index.get_loc(self, key, method, tolerance)
271264

272265
def _maybe_cast_slice_bound(self, label, side: str, kind):

pandas/tests/series/indexing/test_datetime.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from datetime import datetime, timedelta
2+
import re
23

34
import numpy as np
45
import pytest
@@ -380,7 +381,7 @@ def test_datetime_indexing():
380381
s = Series(len(index), index=index)
381382
stamp = Timestamp("1/8/2000")
382383

383-
with pytest.raises(KeyError, match=r"^947289600000000000$"):
384+
with pytest.raises(KeyError, match=re.escape(repr(stamp))):
384385
s[stamp]
385386
s[stamp] = 0
386387
assert s[stamp] == 0
@@ -389,7 +390,7 @@ def test_datetime_indexing():
389390
s = Series(len(index), index=index)
390391
s = s[::-1]
391392

392-
with pytest.raises(KeyError, match=r"^947289600000000000$"):
393+
with pytest.raises(KeyError, match=re.escape(repr(stamp))):
393394
s[stamp]
394395
s[stamp] = 0
395396
assert s[stamp] == 0
@@ -495,8 +496,9 @@ def test_duplicate_dates_indexing(dups):
495496
expected = Series(np.where(mask, 0, ts), index=ts.index)
496497
tm.assert_series_equal(cp, expected)
497498

498-
with pytest.raises(KeyError, match=r"^947116800000000000$"):
499-
ts[datetime(2000, 1, 6)]
499+
key = datetime(2000, 1, 6)
500+
with pytest.raises(KeyError, match=re.escape(repr(key))):
501+
ts[key]
500502

501503
# new index
502504
ts[datetime(2000, 1, 6)] = 0

0 commit comments

Comments
 (0)