Skip to content

Commit fa999f3

Browse files
authored
BUG: raise consistent exception on slicing failure (#38077)
1 parent 090d6a1 commit fa999f3

File tree

5 files changed

+41
-10
lines changed

5 files changed

+41
-10
lines changed

pandas/core/indexes/base.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -3433,11 +3433,11 @@ def _convert_list_indexer(self, keyarr):
34333433
return None
34343434

34353435
@final
3436-
def _invalid_indexer(self, form: str_t, key):
3436+
def _invalid_indexer(self, form: str_t, key) -> TypeError:
34373437
"""
34383438
Consistent invalid indexer message.
34393439
"""
3440-
raise TypeError(
3440+
return TypeError(
34413441
f"cannot do {form} indexing on {type(self).__name__} with these "
34423442
f"indexers [{key}] of type {type(key).__name__}"
34433443
)
@@ -5238,7 +5238,7 @@ def _validate_indexer(self, form: str_t, key, kind: str_t):
52385238
elif is_integer(key):
52395239
pass
52405240
else:
5241-
self._invalid_indexer(form, key)
5241+
raise self._invalid_indexer(form, key)
52425242

52435243
def _maybe_cast_slice_bound(self, label, side: str_t, kind):
52445244
"""
@@ -5267,7 +5267,7 @@ def _maybe_cast_slice_bound(self, label, side: str_t, kind):
52675267
# datetimelike Indexes
52685268
# reject them, if index does not contain label
52695269
if (is_float(label) or is_integer(label)) and label not in self.values:
5270-
self._invalid_indexer("slice", label)
5270+
raise self._invalid_indexer("slice", label)
52715271

52725272
return label
52735273

pandas/core/indexes/datetimes.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,11 @@ def _maybe_cast_slice_bound(self, label, side: str, kind):
717717

718718
if isinstance(label, str):
719719
freq = getattr(self, "freqstr", getattr(self, "inferred_freq", None))
720-
parsed, reso = parsing.parse_time_string(label, freq)
720+
try:
721+
parsed, reso = parsing.parse_time_string(label, freq)
722+
except parsing.DateParseError as err:
723+
raise self._invalid_indexer("slice", label) from err
724+
721725
reso = Resolution.from_attrname(reso)
722726
lower, upper = self._parsed_string_to_bounds(reso, parsed)
723727
# lower, upper form the half-open interval:
@@ -732,7 +736,7 @@ def _maybe_cast_slice_bound(self, label, side: str, kind):
732736
elif isinstance(label, (self._data._recognized_scalars, date)):
733737
self._deprecate_mismatched_indexing(label)
734738
else:
735-
self._invalid_indexer("slice", label)
739+
raise self._invalid_indexer("slice", label)
736740

737741
return self._maybe_cast_for_get_loc(label)
738742

pandas/core/indexes/period.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -578,10 +578,9 @@ def _maybe_cast_slice_bound(self, label, side: str, kind: str):
578578
return bounds[0 if side == "left" else 1]
579579
except ValueError as err:
580580
# string cannot be parsed as datetime-like
581-
# TODO: we need tests for this case
582-
raise KeyError(label) from err
581+
raise self._invalid_indexer("slice", label) from err
583582
elif is_integer(label) or is_float(label):
584-
self._invalid_indexer("slice", label)
583+
raise self._invalid_indexer("slice", label)
585584

586585
return label
587586

pandas/core/indexes/timedeltas.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ def _maybe_cast_slice_bound(self, label, side: str, kind):
223223
else:
224224
return lbound + to_offset(parsed.resolution_string) - Timedelta(1, "ns")
225225
elif not isinstance(label, self._data._recognized_scalars):
226-
self._invalid_indexer("slice", label)
226+
raise self._invalid_indexer("slice", label)
227227

228228
return label
229229

pandas/tests/indexes/period/test_partial_slicing.py

+28
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,34 @@ def test_range_slice_outofbounds(self, make_range):
9090
tm.assert_frame_equal(df["2013-06":"2013-09"], empty)
9191
tm.assert_frame_equal(df["2013-11":"2013-12"], empty)
9292

93+
@pytest.mark.parametrize("make_range", [date_range, period_range])
94+
def test_maybe_cast_slice_bound(self, make_range, frame_or_series):
95+
idx = make_range(start="2013/10/01", freq="D", periods=10)
96+
97+
obj = DataFrame(dict(units=[100 + i for i in range(10)]), index=idx)
98+
if frame_or_series is not DataFrame:
99+
obj = obj["units"]
100+
101+
msg = (
102+
f"cannot do slice indexing on {type(idx).__name__} with "
103+
r"these indexers \[foo\] of type str"
104+
)
105+
106+
# Check the lower-level calls are raising where expected.
107+
with pytest.raises(TypeError, match=msg):
108+
idx._maybe_cast_slice_bound("foo", "left", "loc")
109+
with pytest.raises(TypeError, match=msg):
110+
idx.get_slice_bound("foo", "left", "loc")
111+
112+
with pytest.raises(TypeError, match=msg):
113+
obj["2013/09/30":"foo"]
114+
with pytest.raises(TypeError, match=msg):
115+
obj["foo":"2013/09/30"]
116+
with pytest.raises(TypeError, match=msg):
117+
obj.loc["2013/09/30":"foo"]
118+
with pytest.raises(TypeError, match=msg):
119+
obj.loc["foo":"2013/09/30"]
120+
93121
def test_partial_slice_doesnt_require_monotonicity(self):
94122
# See also: DatetimeIndex test ofm the same name
95123
dti = date_range("2014-01-01", periods=30, freq="30D")

0 commit comments

Comments
 (0)