Skip to content

Commit 15dff11

Browse files
authored
DEPR: kind kwarg in _maybe_cast_slice_bound (pandas-dev#41378)
1 parent 562235d commit 15dff11

File tree

12 files changed

+66
-38
lines changed

12 files changed

+66
-38
lines changed

doc/source/user_guide/scale.rst

+1
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ we need to supply the divisions manually.
345345
Now we can do things like fast random access with ``.loc``.
346346

347347
.. ipython:: python
348+
:okwarning:
348349
349350
ddf.loc["2002-01-01 12:01":"2002-01-01 12:05"].compute()
350351

pandas/core/indexes/base.py

+21-8
Original file line numberDiff line numberDiff line change
@@ -3680,7 +3680,7 @@ def is_int(v):
36803680
)
36813681
indexer = key
36823682
else:
3683-
indexer = self.slice_indexer(start, stop, step, kind=kind)
3683+
indexer = self.slice_indexer(start, stop, step)
36843684

36853685
return indexer
36863686

@@ -5643,7 +5643,7 @@ def slice_indexer(
56435643
>>> idx.slice_indexer(start='b', end=('c', 'g'))
56445644
slice(1, 3, None)
56455645
"""
5646-
start_slice, end_slice = self.slice_locs(start, end, step=step, kind=kind)
5646+
start_slice, end_slice = self.slice_locs(start, end, step=step)
56475647

56485648
# return a slice
56495649
if not is_scalar(start_slice):
@@ -5673,7 +5673,7 @@ def _validate_indexer(self, form: str_t, key, kind: str_t):
56735673
if key is not None and not is_integer(key):
56745674
raise self._invalid_indexer(form, key)
56755675

5676-
def _maybe_cast_slice_bound(self, label, side: str_t, kind):
5676+
def _maybe_cast_slice_bound(self, label, side: str_t, kind=no_default):
56775677
"""
56785678
This function should be overloaded in subclasses that allow non-trivial
56795679
casting on label-slice bounds, e.g. datetime-like indices allowing
@@ -5693,7 +5693,8 @@ def _maybe_cast_slice_bound(self, label, side: str_t, kind):
56935693
-----
56945694
Value of `side` parameter should be validated in caller.
56955695
"""
5696-
assert kind in ["loc", "getitem", None]
5696+
assert kind in ["loc", "getitem", None, no_default]
5697+
self._deprecated_arg(kind, "kind", "_maybe_cast_slice_bound")
56975698

56985699
# We are a plain index here (sub-class override this method if they
56995700
# wish to have special treatment for floats/ints, e.g. Float64Index and
@@ -5718,7 +5719,7 @@ def _searchsorted_monotonic(self, label, side: str_t = "left"):
57185719

57195720
raise ValueError("index must be monotonic increasing or decreasing")
57205721

5721-
def get_slice_bound(self, label, side: str_t, kind) -> int:
5722+
def get_slice_bound(self, label, side: str_t, kind=None) -> int:
57225723
"""
57235724
Calculate slice bound that corresponds to given label.
57245725
@@ -5748,7 +5749,7 @@ def get_slice_bound(self, label, side: str_t, kind) -> int:
57485749

57495750
# For datetime indices label may be a string that has to be converted
57505751
# to datetime boundary according to its resolution.
5751-
label = self._maybe_cast_slice_bound(label, side, kind)
5752+
label = self._maybe_cast_slice_bound(label, side)
57525753

57535754
# we need to look up the label
57545755
try:
@@ -5838,13 +5839,13 @@ def slice_locs(self, start=None, end=None, step=None, kind=None):
58385839

58395840
start_slice = None
58405841
if start is not None:
5841-
start_slice = self.get_slice_bound(start, "left", kind)
5842+
start_slice = self.get_slice_bound(start, "left")
58425843
if start_slice is None:
58435844
start_slice = 0
58445845

58455846
end_slice = None
58465847
if end is not None:
5847-
end_slice = self.get_slice_bound(end, "right", kind)
5848+
end_slice = self.get_slice_bound(end, "right")
58485849
if end_slice is None:
58495850
end_slice = len(self)
58505851

@@ -6176,6 +6177,18 @@ def shape(self) -> Shape:
61766177
# See GH#27775, GH#27384 for history/reasoning in how this is defined.
61776178
return (len(self),)
61786179

6180+
def _deprecated_arg(self, value, name: str_t, methodname: str_t) -> None:
6181+
"""
6182+
Issue a FutureWarning if the arg/kwarg is not no_default.
6183+
"""
6184+
if value is not no_default:
6185+
warnings.warn(
6186+
f"'{name}' argument in {methodname} is deprecated "
6187+
"and will be removed in a future version. Do not pass it.",
6188+
FutureWarning,
6189+
stacklevel=3,
6190+
)
6191+
61796192

61806193
def ensure_index_from_sequences(sequences, names=None):
61816194
"""

pandas/core/indexes/datetimes.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,7 @@ def _maybe_cast_for_get_loc(self, key) -> Timestamp:
724724
key = key.tz_convert(self.tz)
725725
return key
726726

727-
def _maybe_cast_slice_bound(self, label, side: str, kind):
727+
def _maybe_cast_slice_bound(self, label, side: str, kind=lib.no_default):
728728
"""
729729
If label is a string, cast it to datetime according to resolution.
730730
@@ -742,7 +742,8 @@ def _maybe_cast_slice_bound(self, label, side: str, kind):
742742
-----
743743
Value of `side` parameter should be validated in caller.
744744
"""
745-
assert kind in ["loc", "getitem", None]
745+
assert kind in ["loc", "getitem", None, lib.no_default]
746+
self._deprecated_arg(kind, "kind", "_maybe_cast_slice_bound")
746747

747748
if isinstance(label, str):
748749
freq = getattr(self, "freqstr", getattr(self, "inferred_freq", None))
@@ -823,12 +824,12 @@ def check_str_or_none(point):
823824
mask = np.array(True)
824825
deprecation_mask = np.array(True)
825826
if start is not None:
826-
start_casted = self._maybe_cast_slice_bound(start, "left", kind)
827+
start_casted = self._maybe_cast_slice_bound(start, "left")
827828
mask = start_casted <= self
828829
deprecation_mask = start_casted == self
829830

830831
if end is not None:
831-
end_casted = self._maybe_cast_slice_bound(end, "right", kind)
832+
end_casted = self._maybe_cast_slice_bound(end, "right")
832833
mask = (self <= end_casted) & mask
833834
deprecation_mask = (end_casted == self) | deprecation_mask
834835

pandas/core/indexes/interval.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -825,8 +825,9 @@ def _should_fallback_to_positional(self) -> bool:
825825
# positional in this case
826826
return self.dtype.subtype.kind in ["m", "M"]
827827

828-
def _maybe_cast_slice_bound(self, label, side: str, kind):
829-
return getattr(self, side)._maybe_cast_slice_bound(label, side, kind)
828+
def _maybe_cast_slice_bound(self, label, side: str, kind=lib.no_default):
829+
self._deprecated_arg(kind, "kind", "_maybe_cast_slice_bound")
830+
return getattr(self, side)._maybe_cast_slice_bound(label, side)
830831

831832
@Appender(Index._convert_list_indexer.__doc__)
832833
def _convert_list_indexer(self, keyarr):

pandas/core/indexes/multi.py

+6-8
Original file line numberDiff line numberDiff line change
@@ -2716,7 +2716,7 @@ def _get_indexer(
27162716
return ensure_platform_int(indexer)
27172717

27182718
def get_slice_bound(
2719-
self, label: Hashable | Sequence[Hashable], side: str, kind: str
2719+
self, label: Hashable | Sequence[Hashable], side: str, kind: str | None = None
27202720
) -> int:
27212721
"""
27222722
For an ordered MultiIndex, compute slice bound
@@ -2729,7 +2729,7 @@ def get_slice_bound(
27292729
----------
27302730
label : object or tuple of objects
27312731
side : {'left', 'right'}
2732-
kind : {'loc', 'getitem'}
2732+
kind : {'loc', 'getitem', None}
27332733
27342734
Returns
27352735
-------
@@ -2747,13 +2747,13 @@ def get_slice_bound(
27472747
Get the locations from the leftmost 'b' in the first level
27482748
until the end of the multiindex:
27492749
2750-
>>> mi.get_slice_bound('b', side="left", kind="loc")
2750+
>>> mi.get_slice_bound('b', side="left")
27512751
1
27522752
27532753
Like above, but if you get the locations from the rightmost
27542754
'b' in the first level and 'f' in the second level:
27552755
2756-
>>> mi.get_slice_bound(('b','f'), side="right", kind="loc")
2756+
>>> mi.get_slice_bound(('b','f'), side="right")
27572757
3
27582758
27592759
See Also
@@ -2820,7 +2820,7 @@ def slice_locs(self, start=None, end=None, step=None, kind=None):
28202820
"""
28212821
# This function adds nothing to its parent implementation (the magic
28222822
# happens in get_slice_bound method), but it adds meaningful doc.
2823-
return super().slice_locs(start, end, step, kind=kind)
2823+
return super().slice_locs(start, end, step)
28242824

28252825
def _partial_tup_index(self, tup, side="left"):
28262826
if len(tup) > self._lexsort_depth:
@@ -3206,9 +3206,7 @@ def convert_indexer(start, stop, step, indexer=indexer, codes=level_codes):
32063206

32073207
# we have a partial slice (like looking up a partial date
32083208
# string)
3209-
start = stop = level_index.slice_indexer(
3210-
key.start, key.stop, key.step, kind="loc"
3211-
)
3209+
start = stop = level_index.slice_indexer(key.start, key.stop, key.step)
32123210
step = start.step
32133211

32143212
if isinstance(start, slice) or isinstance(stop, slice):

pandas/core/indexes/numeric.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,9 @@ def _validate_dtype(cls, dtype: Dtype | None) -> None:
112112
# Indexing Methods
113113

114114
@doc(Index._maybe_cast_slice_bound)
115-
def _maybe_cast_slice_bound(self, label, side: str, kind):
116-
assert kind in ["loc", "getitem", None]
115+
def _maybe_cast_slice_bound(self, label, side: str, kind=lib.no_default):
116+
assert kind in ["loc", "getitem", None, lib.no_default]
117+
self._deprecated_arg(kind, "kind", "_maybe_cast_slice_bound")
117118

118119
# we will try to coerce to integers
119120
return self._maybe_cast_indexer(label)
@@ -346,7 +347,7 @@ def _convert_slice_indexer(self, key: slice, kind: str):
346347

347348
# We always treat __getitem__ slicing as label-based
348349
# translate to locations
349-
return self.slice_indexer(key.start, key.stop, key.step, kind=kind)
350+
return self.slice_indexer(key.start, key.stop, key.step)
350351

351352
# ----------------------------------------------------------------
352353

pandas/core/indexes/period.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ def get_loc(self, key, method=None, tolerance=None):
531531
except KeyError as err:
532532
raise KeyError(orig_key) from err
533533

534-
def _maybe_cast_slice_bound(self, label, side: str, kind: str):
534+
def _maybe_cast_slice_bound(self, label, side: str, kind=lib.no_default):
535535
"""
536536
If label is a string or a datetime, cast it to Period.ordinal according
537537
to resolution.
@@ -540,7 +540,7 @@ def _maybe_cast_slice_bound(self, label, side: str, kind: str):
540540
----------
541541
label : object
542542
side : {'left', 'right'}
543-
kind : {'loc', 'getitem'}
543+
kind : {'loc', 'getitem'}, or None
544544
545545
Returns
546546
-------
@@ -551,7 +551,8 @@ def _maybe_cast_slice_bound(self, label, side: str, kind: str):
551551
Value of `side` parameter should be validated in caller.
552552
553553
"""
554-
assert kind in ["loc", "getitem"]
554+
assert kind in ["loc", "getitem", None, lib.no_default]
555+
self._deprecated_arg(kind, "kind", "_maybe_cast_slice_bound")
555556

556557
if isinstance(label, datetime):
557558
return Period(label, freq=self.freq)

pandas/core/indexes/timedeltas.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ def get_loc(self, key, method=None, tolerance=None):
192192

193193
return Index.get_loc(self, key, method, tolerance)
194194

195-
def _maybe_cast_slice_bound(self, label, side: str, kind):
195+
def _maybe_cast_slice_bound(self, label, side: str, kind=lib.no_default):
196196
"""
197197
If label is a string, cast it to timedelta according to resolution.
198198
@@ -206,7 +206,8 @@ def _maybe_cast_slice_bound(self, label, side: str, kind):
206206
-------
207207
label : object
208208
"""
209-
assert kind in ["loc", "getitem", None]
209+
assert kind in ["loc", "getitem", None, lib.no_default]
210+
self._deprecated_arg(kind, "kind", "_maybe_cast_slice_bound")
210211

211212
if isinstance(label, str):
212213
parsed = Timedelta(label)

pandas/core/indexing.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -1170,9 +1170,7 @@ def _get_slice_axis(self, slice_obj: slice, axis: int):
11701170
return obj.copy(deep=False)
11711171

11721172
labels = obj._get_axis(axis)
1173-
indexer = labels.slice_indexer(
1174-
slice_obj.start, slice_obj.stop, slice_obj.step, kind="loc"
1175-
)
1173+
indexer = labels.slice_indexer(slice_obj.start, slice_obj.stop, slice_obj.step)
11761174

11771175
if isinstance(indexer, slice):
11781176
return self.obj._slice(indexer, axis=axis)

pandas/tests/indexes/datetimes/test_indexing.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -679,18 +679,18 @@ def test_maybe_cast_slice_bounds_empty(self):
679679
# GH#14354
680680
empty_idx = date_range(freq="1H", periods=0, end="2015")
681681

682-
right = empty_idx._maybe_cast_slice_bound("2015-01-02", "right", "loc")
682+
right = empty_idx._maybe_cast_slice_bound("2015-01-02", "right")
683683
exp = Timestamp("2015-01-02 23:59:59.999999999")
684684
assert right == exp
685685

686-
left = empty_idx._maybe_cast_slice_bound("2015-01-02", "left", "loc")
686+
left = empty_idx._maybe_cast_slice_bound("2015-01-02", "left")
687687
exp = Timestamp("2015-01-02 00:00:00")
688688
assert left == exp
689689

690690
def test_maybe_cast_slice_duplicate_monotonic(self):
691691
# https://github.com/pandas-dev/pandas/issues/16515
692692
idx = DatetimeIndex(["2017", "2017"])
693-
result = idx._maybe_cast_slice_bound("2017-01-01", "left", "loc")
693+
result = idx._maybe_cast_slice_bound("2017-01-01", "left")
694694
expected = Timestamp("2017-01-01")
695695
assert result == expected
696696

pandas/tests/indexes/period/test_partial_slicing.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,9 @@ def test_maybe_cast_slice_bound(self, make_range, frame_or_series):
110110

111111
# Check the lower-level calls are raising where expected.
112112
with pytest.raises(TypeError, match=msg):
113-
idx._maybe_cast_slice_bound("foo", "left", "loc")
113+
idx._maybe_cast_slice_bound("foo", "left")
114114
with pytest.raises(TypeError, match=msg):
115-
idx.get_slice_bound("foo", "left", "loc")
115+
idx.get_slice_bound("foo", "left")
116116

117117
with pytest.raises(TypeError, match=msg):
118118
obj["2013/09/30":"foo"]

pandas/tests/indexes/test_indexing.py

+13
Original file line numberDiff line numberDiff line change
@@ -259,3 +259,16 @@ def test_getitem_deprecated_float(idx):
259259

260260
expected = idx[1]
261261
assert result == expected
262+
263+
264+
def test_maybe_cast_slice_bound_kind_deprecated(index):
265+
if not len(index):
266+
return
267+
268+
with tm.assert_produces_warning(FutureWarning):
269+
# passed as keyword
270+
index._maybe_cast_slice_bound(index[0], "left", kind="loc")
271+
272+
with tm.assert_produces_warning(FutureWarning):
273+
# pass as positional
274+
index._maybe_cast_slice_bound(index[0], "left", "loc")

0 commit comments

Comments
 (0)