Skip to content

BUG: fix .loc.__setitem__ not raising when using too many indexers #44656

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Jan 30, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v1.4.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ Indexing
- Bug in indexing on columns with ``loc`` or ``iloc`` using a slice with a negative step with ``ExtensionDtype`` columns incorrectly raising (:issue:`44551`)
- Bug in :meth:`IntervalIndex.get_indexer_non_unique` returning boolean mask instead of array of integers for a non unique and non monotonic index (:issue:`44084`)
- Bug in :meth:`IntervalIndex.get_indexer_non_unique` not handling targets of ``dtype`` 'object' with NaNs correctly (:issue:`44482`)
-
- Bug in :meth:`Series.loc.__setitem__` and :meth:`Series.loc.__getitem__` not raising when using multiple keys without using a :class:`MultiIndex` (:issue:`13831`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah let's move this to 1.5

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, I moved whatsnew


Missing
^^^^^^^
Expand Down
12 changes: 10 additions & 2 deletions pandas/core/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -911,7 +911,7 @@ def _getitem_nested_tuple(self, tup: tuple):
# we are only getting non-hashable tuples, in particular ones
# that themselves contain a slice entry
# See test_loc_series_getitem_too_many_dimensions
raise ValueError("Too many indices")
raise IndexingError("Too many indexers")

# this is a series with a multi-index specified a tuple of
# selectors
Expand Down Expand Up @@ -1231,6 +1231,14 @@ def _convert_to_indexer(self, key, axis: int):
is_int_index = labels.is_integer()
is_int_positional = is_integer(key) and not is_int_index

if (
isinstance(key, tuple)
and not isinstance(labels, MultiIndex)
and self.ndim < 2
and len(key) > 1
):
raise IndexingError("Too many indexers")

if is_scalar(key) or (isinstance(labels, MultiIndex) and is_hashable(key)):
# Otherwise get_loc will raise InvalidIndexError

Expand Down Expand Up @@ -1262,7 +1270,7 @@ def _convert_to_indexer(self, key, axis: int):
if is_nested_tuple(key, labels):
if self.ndim == 1 and any(isinstance(k, tuple) for k in key):
# GH#35349 Raise if tuple in tuple for series
raise ValueError("Too many indices")
raise IndexingError("Too many indexers")
return labels.get_locs(key)

elif is_list_like_indexer(key):
Expand Down
22 changes: 22 additions & 0 deletions pandas/tests/indexing/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
)
import pandas._testing as tm
from pandas.core.api import Float64Index
from pandas.core.indexing import IndexingError
from pandas.tests.indexing.common import _mklbl
from pandas.tests.indexing.test_floats import gen_obj

Expand Down Expand Up @@ -978,3 +979,24 @@ def test_extension_array_cross_section_converts():

result = df.iloc[0]
tm.assert_series_equal(result, expected)


@pytest.mark.parametrize(
"ser, keys",
[(Series([10]), (0, 0)), (Series([1, 2, 3], index=list("abc")), (0, 1))],
)
def test_ser_indexer_exceeds_dimensions(ser, keys, indexer_sli):
# GH#13831
if indexer_sli == tm.setitem:
return

exp_err, exp_msg = IndexingError, "Too many indexers"
with pytest.raises(exp_err, match=exp_msg):
indexer_sli(ser)[keys]

if indexer_sli == tm.iloc:
# For iloc.__setitem__ we let numpy handle the error reporting.
exp_err, exp_msg = IndexError, "too many indices for array"

with pytest.raises(exp_err, match=exp_msg):
indexer_sli(ser)[keys] = 0
18 changes: 15 additions & 3 deletions pandas/tests/indexing/test_loc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2685,6 +2685,18 @@ def test_loc_with_period_index_indexer():
tm.assert_frame_equal(df, df.loc[list(idx)])


def test_loc_setitem_multiindex_timestamp():
# GH#13831
vals = np.random.randn(8, 6)
idx = date_range("1/1/2000", periods=8)
cols = ["A", "B", "C", "D", "E", "F"]
exp = DataFrame(vals, index=idx, columns=cols)
exp.loc[exp.index[1], ("A", "B")] = np.nan
vals[1][0:2] = np.nan
res = DataFrame(vals, index=idx, columns=cols)
tm.assert_frame_equal(res, exp)


def test_loc_getitem_multiindex_tuple_level():
# GH#27591
lev1 = ["a", "b", "c"]
Expand Down Expand Up @@ -2889,11 +2901,11 @@ def test_loc_series_getitem_too_many_dimensions(self, indexer):
index=MultiIndex.from_tuples([("A", "0"), ("A", "1"), ("B", "0")]),
data=[21, 22, 23],
)
msg = "Too many indices"
with pytest.raises(ValueError, match=msg):
msg = "Too many indexers"
with pytest.raises(IndexingError, match=msg):
ser.loc[indexer, :]

with pytest.raises(ValueError, match=msg):
with pytest.raises(IndexingError, match=msg):
ser.loc[indexer, :] = 1

def test_loc_setitem(self, string_series):
Expand Down