Skip to content

Commit b617bee

Browse files
authored
Bug in loc did not raise KeyError when missing combination with slice(None) was given (#37764)
1 parent 10bee10 commit b617bee

File tree

3 files changed

+34
-5
lines changed

3 files changed

+34
-5
lines changed

doc/source/whatsnew/v1.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,7 @@ Indexing
612612
- Bug in :meth:`DataFrame.reindex` raising ``IndexingError`` wrongly for empty :class:`DataFrame` with ``tolerance`` not None or ``method="nearest"`` (:issue:`27315`)
613613
- Bug in indexing on a :class:`Series` or :class:`DataFrame` with a :class:`CategoricalIndex` using listlike indexer that contains elements that are in the index's ``categories`` but not in the index itself failing to raise ``KeyError`` (:issue:`37901`)
614614
- Bug in :meth:`DataFrame.iloc` and :meth:`Series.iloc` aligning objects in ``__setitem__`` (:issue:`22046`)
615+
- Bug in :meth:`DataFrame.loc` did not raise ``KeyError`` when missing combination was given with ``slice(None)`` for remaining levels (:issue:`19556`)
615616

616617
Missing
617618
^^^^^^^

pandas/core/indexes/multi.py

+14-5
Original file line numberDiff line numberDiff line change
@@ -3111,19 +3111,26 @@ def _convert_to_indexer(r) -> Int64Index:
31113111
r = r.nonzero()[0]
31123112
return Int64Index(r)
31133113

3114-
def _update_indexer(idxr: Optional[Index], indexer: Optional[Index]) -> Index:
3114+
def _update_indexer(
3115+
idxr: Optional[Index], indexer: Optional[Index], key
3116+
) -> Index:
31153117
if indexer is None:
31163118
indexer = Index(np.arange(n))
31173119
if idxr is None:
31183120
return indexer
3119-
return indexer.intersection(idxr)
3121+
indexer_intersection = indexer.intersection(idxr)
3122+
if indexer_intersection.empty and not idxr.empty and not indexer.empty:
3123+
raise KeyError(key)
3124+
return indexer_intersection
31203125

31213126
for i, k in enumerate(seq):
31223127

31233128
if com.is_bool_indexer(k):
31243129
# a boolean indexer, must be the same length!
31253130
k = np.asarray(k)
3126-
indexer = _update_indexer(_convert_to_indexer(k), indexer=indexer)
3131+
indexer = _update_indexer(
3132+
_convert_to_indexer(k), indexer=indexer, key=seq
3133+
)
31273134

31283135
elif is_list_like(k):
31293136
# a collection of labels to include from this level (these
@@ -3143,14 +3150,14 @@ def _update_indexer(idxr: Optional[Index], indexer: Optional[Index]) -> Index:
31433150
continue
31443151

31453152
if indexers is not None:
3146-
indexer = _update_indexer(indexers, indexer=indexer)
3153+
indexer = _update_indexer(indexers, indexer=indexer, key=seq)
31473154
else:
31483155
# no matches we are done
31493156
return np.array([], dtype=np.int64)
31503157

31513158
elif com.is_null_slice(k):
31523159
# empty slice
3153-
indexer = _update_indexer(None, indexer=indexer)
3160+
indexer = _update_indexer(None, indexer=indexer, key=seq)
31543161

31553162
elif isinstance(k, slice):
31563163

@@ -3160,6 +3167,7 @@ def _update_indexer(idxr: Optional[Index], indexer: Optional[Index]) -> Index:
31603167
self._get_level_indexer(k, level=i, indexer=indexer)
31613168
),
31623169
indexer=indexer,
3170+
key=seq,
31633171
)
31643172
else:
31653173
# a single label
@@ -3168,6 +3176,7 @@ def _update_indexer(idxr: Optional[Index], indexer: Optional[Index]) -> Index:
31683176
self.get_loc_level(k, level=i, drop_level=False)[0]
31693177
),
31703178
indexer=indexer,
3179+
key=seq,
31713180
)
31723181

31733182
# empty indexer

pandas/tests/indexing/multiindex/test_loc.py

+19
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,25 @@ def test_missing_key_raises_keyerror2(self):
608608
with pytest.raises(KeyError, match=r"\(0, 3\)"):
609609
ser.loc[0, 3]
610610

611+
def test_missing_key_combination(self):
612+
# GH: 19556
613+
mi = MultiIndex.from_arrays(
614+
[
615+
np.array(["a", "a", "b", "b"]),
616+
np.array(["1", "2", "2", "3"]),
617+
np.array(["c", "d", "c", "d"]),
618+
],
619+
names=["one", "two", "three"],
620+
)
621+
df = DataFrame(np.random.rand(4, 3), index=mi)
622+
msg = r"\('b', '1', slice\(None, None, None\)\)"
623+
with pytest.raises(KeyError, match=msg):
624+
df.loc[("b", "1", slice(None)), :]
625+
with pytest.raises(KeyError, match=msg):
626+
df.index.get_locs(("b", "1", slice(None)))
627+
with pytest.raises(KeyError, match=r"\('b', '1'\)"):
628+
df.loc[("b", "1"), :]
629+
611630

612631
def test_getitem_loc_commutability(multiindex_year_month_day_dataframe_random_data):
613632
df = multiindex_year_month_day_dataframe_random_data

0 commit comments

Comments
 (0)