Skip to content

Commit 1a48854

Browse files
jbrockmendelpartevWillAyd
authored andcommitted
BUG: Series.__setitem__[listlike_of_integers] with IntervalIndex (pandas-dev#33473)
* BUG: Series.__getitem__ with MultiIndex and leading integer level * dedicated tests * whatnsew * test * REF: collect DataFrame.__setitem__ tests (pandas-dev#33408) * use https link for Anaconda (pandas-dev#33413) * unpinned 37 (pandas-dev#33423) * revert * BUG: Series.__setitem__[listlike_of_integers] with IntervalIndex] * whatsnew Co-authored-by: partev <[email protected]> Co-authored-by: William Ayd <[email protected]>
1 parent 546a7b5 commit 1a48854

File tree

8 files changed

+22
-14
lines changed

8 files changed

+22
-14
lines changed

doc/source/whatsnew/v1.1.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,7 @@ Indexing
525525
- Bug in `Series.__getitem__` with an integer key and a :class:`MultiIndex` with leading integer level failing to raise ``KeyError`` if the key is not present in the first level (:issue:`33355`)
526526
- Bug in :meth:`DataFrame.iloc` when slicing a single column-:class:`DataFrame`` with ``ExtensionDtype`` (e.g. ``df.iloc[:, :1]``) returning an invalid result (:issue:`32957`)
527527
- Bug in :meth:`DatetimeIndex.insert` and :meth:`TimedeltaIndex.insert` causing index ``freq`` to be lost when setting an element into an empty :class:`Series` (:issue:33573`)
528+
- Bug in :meth:`Series.__setitem__` with an :class:`IntervalIndex` and a list-like key of integers (:issue:`33473`)
528529

529530
Missing
530531
^^^^^^^

pandas/core/indexes/base.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -4595,9 +4595,9 @@ def _check_indexing_error(self, key):
45954595

45964596
def _should_fallback_to_positional(self) -> bool:
45974597
"""
4598-
If an integer key is not found, should we fall back to positional indexing?
4598+
Should an integer key be treated as positional?
45994599
"""
4600-
if len(self) > 0 and (self.holds_integer() or self.is_boolean()):
4600+
if self.holds_integer() or self.is_boolean():
46014601
return False
46024602
return True
46034603

pandas/core/indexes/interval.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ def is_overlapping(self) -> bool:
514514
# GH 23309
515515
return self._engine.is_overlapping
516516

517-
def _should_fallback_to_positional(self):
517+
def _should_fallback_to_positional(self) -> bool:
518518
# integer lookups in Series.__getitem__ are unambiguously
519519
# positional in this case
520520
return self.dtype.subtype.kind in ["m", "M"]

pandas/core/indexes/multi.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -2342,10 +2342,8 @@ def _check_indexing_error(self, key):
23422342

23432343
def _should_fallback_to_positional(self) -> bool:
23442344
"""
2345-
If an integer key is not found, should we fall back to positional indexing?
2345+
Should integer key(s) be treated as positional?
23462346
"""
2347-
if not self.nlevels:
2348-
return False
23492347
# GH#33355
23502348
return self.levels[0]._should_fallback_to_positional()
23512349

pandas/core/indexes/numeric.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ def astype(self, dtype, copy=True):
376376
# Indexing Methods
377377

378378
@doc(Index._should_fallback_to_positional)
379-
def _should_fallback_to_positional(self):
379+
def _should_fallback_to_positional(self) -> bool:
380380
return False
381381

382382
@doc(Index._convert_slice_indexer)

pandas/core/series.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@
7979
from pandas.core.indexes.api import (
8080
Float64Index,
8181
Index,
82-
IntervalIndex,
8382
InvalidIndexError,
8483
MultiIndex,
8584
ensure_index,
@@ -945,9 +944,7 @@ def _get_with(self, key):
945944
if key_type == "integer":
946945
# We need to decide whether to treat this as a positional indexer
947946
# (i.e. self.iloc) or label-based (i.e. self.loc)
948-
if self.index.is_integer() or self.index.is_floating():
949-
return self.loc[key]
950-
elif isinstance(self.index, IntervalIndex):
947+
if not self.index._should_fallback_to_positional():
951948
return self.loc[key]
952949
else:
953950
return self.iloc[key]
@@ -1070,7 +1067,7 @@ def _set_with(self, key, value):
10701067
# Note: key_type == "boolean" should not occur because that
10711068
# should be caught by the is_bool_indexer check in __setitem__
10721069
if key_type == "integer":
1073-
if self.index.inferred_type == "integer":
1070+
if not self.index._should_fallback_to_positional():
10741071
self._set_labels(key, value)
10751072
else:
10761073
self._set_values(key, value)

pandas/tests/series/indexing/test_getitem.py

+12
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,18 @@ def test_getitem_intlist_intindex_periodvalues(self):
9090
tm.assert_series_equal(result, exp)
9191
assert result.dtype == "Period[D]"
9292

93+
@pytest.mark.parametrize("box", [list, np.array, pd.Index])
94+
def test_getitem_intlist_intervalindex_non_int(self, box):
95+
# GH#33404 fall back to positional since ints are unambiguous
96+
dti = date_range("2000-01-03", periods=3)
97+
ii = pd.IntervalIndex.from_breaks(dti)
98+
ser = Series(range(len(ii)), index=ii)
99+
100+
expected = ser.iloc[:1]
101+
key = box([0])
102+
result = ser[key]
103+
tm.assert_series_equal(result, expected)
104+
93105

94106
def test_getitem_generator(string_series):
95107
gen = (x > 0 for x in string_series)

pandas/tests/series/indexing/test_indexing.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,9 @@ def test_getitem_out_of_bounds(datetime_series):
159159
datetime_series[len(datetime_series)]
160160

161161
# GH #917
162-
msg = r"index -\d+ is out of bounds for axis 0 with size \d+"
162+
# With a RangeIndex, an int key gives a KeyError
163163
s = Series([], dtype=object)
164-
with pytest.raises(IndexError, match=msg):
164+
with pytest.raises(KeyError, match="-1"):
165165
s[-1]
166166

167167

0 commit comments

Comments
 (0)