Skip to content

Commit

Permalink
Backport PR on Branch 1.5.x (REV: revert deprecation of Series.__geti…
Browse files Browse the repository at this point in the history
…tem__ slicing with IntegerIndex) (#50694)

* REV: revert deprecation of Series.__getitem__ slicing with IntegerIndex (#50283)

(cherry picked from commit 1613f26)

* Avoid unrelated changes

* Fix

Co-authored-by: jbrockmendel <jbrockmendel@gmail.com>
  • Loading branch information
phofl and jbrockmendel committed Jan 14, 2023
1 parent 71db310 commit 54b4037
Show file tree
Hide file tree
Showing 10 changed files with 15 additions and 68 deletions.
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v1.5.3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Other
you may see a ``sqlalchemy.exc.RemovedIn20Warning``. These warnings can be safely ignored for the SQLAlchemy 1.4.x releases
as pandas works toward compatibility with SQLAlchemy 2.0.

-
- Reverted deprecation (:issue:`45324`) of behavior of :meth:`Series.__getitem__` and :meth:`Series.__setitem__` slicing with an integer :class:`Index`; this will remain positional (:issue:`49612`)
-

.. ---------------------------------------------------------------------------
Expand Down
47 changes: 2 additions & 45 deletions pandas/core/indexes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@
ABCDatetimeIndex,
ABCMultiIndex,
ABCPeriodIndex,
ABCRangeIndex,
ABCSeries,
ABCTimedeltaIndex,
)
Expand Down Expand Up @@ -4213,7 +4212,7 @@ def _validate_positional_slice(self, key: slice) -> None:
self._validate_indexer("positional", key.stop, "iloc")
self._validate_indexer("positional", key.step, "iloc")

def _convert_slice_indexer(self, key: slice, kind: str_t, is_frame: bool = False):
def _convert_slice_indexer(self, key: slice, kind: str_t):
"""
Convert a slice indexer.
Expand All @@ -4224,9 +4223,6 @@ def _convert_slice_indexer(self, key: slice, kind: str_t, is_frame: bool = False
----------
key : label of the slice bound
kind : {'loc', 'getitem'}
is_frame : bool, default False
Whether this is a slice called on DataFrame.__getitem__
as opposed to Series.__getitem__
"""
assert kind in ["loc", "getitem"], kind

Expand All @@ -4248,46 +4244,7 @@ def is_int(v):
is_positional = is_index_slice and ints_are_positional

if kind == "getitem":
"""
called from the getitem slicers, validate that we are in fact
integers
"""
if self.is_integer():
if is_frame:
# unambiguously positional, no deprecation
pass
elif start is None and stop is None:
# label-based vs positional is irrelevant
pass
elif isinstance(self, ABCRangeIndex) and self._range == range(
len(self)
):
# In this case there is no difference between label-based
# and positional, so nothing will change.
pass
elif (
self.dtype.kind in ["i", "u"]
and self._is_strictly_monotonic_increasing
and len(self) > 0
and self[0] == 0
and self[-1] == len(self) - 1
):
# We are range-like, e.g. created with Index(np.arange(N))
pass
elif not is_index_slice:
# we're going to raise, so don't bother warning, e.g.
# test_integer_positional_indexing
pass
else:
warnings.warn(
"The behavior of `series[i:j]` with an integer-dtype index "
"is deprecated. In a future version, this will be treated "
"as *label-based* indexing, consistent with e.g. `series[i]` "
"lookups. To retain the old behavior, use `series.iloc[i:j]`. "
"To get the future behavior, use `series.loc[i:j]`.",
FutureWarning,
stacklevel=find_stack_level(),
)
# called from the getitem slicers, validate that we are in fact integers
if self.is_integer() or is_index_slice:
# Note: these checks are redundant if we know is_index_slice
self._validate_indexer("slice", key.start, "getitem")
Expand Down
4 changes: 2 additions & 2 deletions pandas/core/indexes/interval.py
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,7 @@ def _index_as_unique(self) -> bool:
"cannot handle overlapping indices; use IntervalIndex.get_indexer_non_unique"
)

def _convert_slice_indexer(self, key: slice, kind: str, is_frame: bool = False):
def _convert_slice_indexer(self, key: slice, kind: str):
if not (key.step is None or key.step == 1):
# GH#31658 if label-based, we require step == 1,
# if positional, we disallow float start/stop
Expand All @@ -791,7 +791,7 @@ def _convert_slice_indexer(self, key: slice, kind: str, is_frame: bool = False):
# i.e. this cannot be interpreted as a positional slice
raise ValueError(msg)

return super()._convert_slice_indexer(key, kind, is_frame=is_frame)
return super()._convert_slice_indexer(key, kind)

@cache_readonly
def _should_fallback_to_positional(self) -> bool:
Expand Down
4 changes: 2 additions & 2 deletions pandas/core/indexes/numeric.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ def _should_fallback_to_positional(self) -> bool:
return False

@doc(Index._convert_slice_indexer)
def _convert_slice_indexer(self, key: slice, kind: str, is_frame: bool = False):
def _convert_slice_indexer(self, key: slice, kind: str):
# TODO(2.0): once #45324 deprecation is enforced we should be able
# to simplify this.
if is_float_dtype(self.dtype):
Expand All @@ -231,7 +231,7 @@ def _convert_slice_indexer(self, key: slice, kind: str, is_frame: bool = False):
# translate to locations
return self.slice_indexer(key.start, key.stop, key.step)

return super()._convert_slice_indexer(key, kind=kind, is_frame=is_frame)
return super()._convert_slice_indexer(key, kind=kind)

@doc(Index._maybe_cast_slice_bound)
def _maybe_cast_slice_bound(self, label, side: str, kind=lib.no_default):
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2491,7 +2491,7 @@ def convert_to_index_sliceable(obj: DataFrame, key):
"""
idx = obj.index
if isinstance(key, slice):
return idx._convert_slice_indexer(key, kind="getitem", is_frame=True)
return idx._convert_slice_indexer(key, kind="getitem")

elif isinstance(key, str):

Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/extension/base/getitem.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,7 @@ def test_get(self, data):
expected = s.iloc[[2, 3]]
self.assert_series_equal(result, expected)

with tm.assert_produces_warning(FutureWarning, match="label-based"):
result = s.get(slice(2))
result = s.get(slice(2))
expected = s.iloc[[0, 1]]
self.assert_series_equal(result, expected)

Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/indexing/test_floats.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,7 @@ def test_integer_positional_indexing(self, idx):
"""
s = Series(range(2, 6), index=range(2, 6))

with tm.assert_produces_warning(FutureWarning, match="label-based"):
result = s[2:4]
result = s[2:4]
expected = s.iloc[2:4]
tm.assert_series_equal(result, expected)

Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/series/indexing/test_get.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,7 @@ def test_get_with_ea(arr):
expected = ser.iloc[[2, 3]]
tm.assert_series_equal(result, expected)

with tm.assert_produces_warning(FutureWarning, match="label-based"):
result = ser.get(slice(2))
result = ser.get(slice(2))
expected = ser.iloc[[0, 1]]
tm.assert_series_equal(result, expected)

Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/series/indexing/test_getitem.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,8 +338,7 @@ def test_getitem_slice_bug(self):
def test_getitem_slice_integers(self):
ser = Series(np.random.randn(8), index=[2, 4, 6, 8, 10, 12, 14, 16])

with tm.assert_produces_warning(FutureWarning, match="label-based"):
result = ser[:4]
result = ser[:4]
expected = Series(ser.values[:4], index=[2, 4, 6, 8])
tm.assert_series_equal(result, expected)

Expand Down
12 changes: 3 additions & 9 deletions pandas/tests/series/indexing/test_setitem.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,15 +220,9 @@ def test_setitem_slice(self):
def test_setitem_slice_integers(self):
ser = Series(np.random.randn(8), index=[2, 4, 6, 8, 10, 12, 14, 16])

msg = r"In a future version, this will be treated as \*label-based\* indexing"
with tm.assert_produces_warning(FutureWarning, match=msg):
ser[:4] = 0
with tm.assert_produces_warning(
FutureWarning, match=msg, check_stacklevel=False
):
assert (ser[:4] == 0).all()
with tm.assert_produces_warning(FutureWarning, match=msg):
assert not (ser[4:] == 0).any()
ser[:4] = 0
assert (ser[:4] == 0).all()
assert not (ser[4:] == 0).any()

def test_setitem_slicestep(self):
# caught this bug when writing tests
Expand Down

0 comments on commit 54b4037

Please sign in to comment.