diff --git a/doc/source/whatsnew/v0.25.0.rst b/doc/source/whatsnew/v0.25.0.rst index c25bc87a00d2e..e73c5c441608a 100644 --- a/doc/source/whatsnew/v0.25.0.rst +++ b/doc/source/whatsnew/v0.25.0.rst @@ -327,6 +327,7 @@ Indexing ^^^^^^^^ - Improved exception message when calling :meth:`DataFrame.iloc` with a list of non-numeric objects (:issue:`25753`). +- Bug in :meth:`DataFrame.loc` and :meth:`Series.loc` where ``KeyError`` was not raised for a ``MultiIndex`` when the key was less than or equal to the number of levels in the :class:`MultiIndex` (:issue:`14885`). - Bug in which :meth:`DataFrame.append` produced an erroneous warning indicating that a ``KeyError`` will be thrown in the future when the data to be appended contains new columns (:issue:`22252`). - diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 68d4e746f72ad..b42745b1a6619 100755 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -944,6 +944,12 @@ def _handle_lowerdim_multi_index_axis0(self, tup): except TypeError: # slices are unhashable pass + except KeyError as ek: + # raise KeyError if number of indexers match + # else IndexingError will be raised + if (len(tup) <= self.obj.index.nlevels + and len(tup) > self.obj.ndim): + raise ek except Exception as e1: if isinstance(tup[0], (slice, Index)): raise IndexingError("Handle elsewhere") diff --git a/pandas/tests/indexing/multiindex/test_getitem.py b/pandas/tests/indexing/multiindex/test_getitem.py index 1080c3ecdcf1f..db588deab30f1 100644 --- a/pandas/tests/indexing/multiindex/test_getitem.py +++ b/pandas/tests/indexing/multiindex/test_getitem.py @@ -85,7 +85,8 @@ def test_series_getitem_returns_scalar( @pytest.mark.parametrize('indexer,expected_error,expected_error_msg', [ (lambda s: s.__getitem__((2000, 3, 4)), KeyError, r"^356L?$"), (lambda s: s[(2000, 3, 4)], KeyError, r"^356L?$"), - (lambda s: s.loc[(2000, 3, 4)], IndexingError, 'Too many indexers'), + (lambda s: s.loc[(2000, 3, 4)], KeyError, r"^356L?$"), + (lambda s: s.loc[(2000, 3, 4, 5)], IndexingError, 'Too many indexers'), (lambda s: s.__getitem__(len(s)), IndexError, 'index out of bounds'), (lambda s: s[len(s)], IndexError, 'index out of bounds'), (lambda s: s.iloc[len(s)], IndexError, diff --git a/pandas/tests/indexing/multiindex/test_loc.py b/pandas/tests/indexing/multiindex/test_loc.py index 8345940a15d43..90d9791107eb3 100644 --- a/pandas/tests/indexing/multiindex/test_loc.py +++ b/pandas/tests/indexing/multiindex/test_loc.py @@ -6,6 +6,7 @@ import pandas as pd from pandas import DataFrame, Index, MultiIndex, Series +from pandas.core.indexing import IndexingError from pandas.util import testing as tm @@ -130,6 +131,18 @@ def test_loc_multiindex(self): with pytest.raises(KeyError, match=r"^2L?$"): mi_int.ix[2] + def test_loc_multiindex_too_many_dims(self): + # GH 14885 + s = Series(range(8), index=MultiIndex.from_product( + [['a', 'b'], ['c', 'd'], ['e', 'f']])) + + with pytest.raises(KeyError, match=r"^\('a', 'b'\)$"): + s.loc['a', 'b'] + with pytest.raises(KeyError, match=r"^\('a', 'd', 'g'\)$"): + s.loc['a', 'd', 'g'] + with pytest.raises(IndexingError, match='Too many indexers'): + s.loc['a', 'd', 'g', 'j'] + def test_loc_multiindex_indexer_none(self): # GH6788