From 85858d63abcc5319f2e544263f2eb99d11c9b239 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Tue, 18 Feb 2020 18:17:57 -0800 Subject: [PATCH 1/2] CLN: simplify iloc._get_setitem_indexer --- pandas/core/indexing.py | 16 ++++--------- pandas/tests/indexing/test_floats.py | 36 ++++++++++------------------ 2 files changed, 18 insertions(+), 34 deletions(-) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index d3e75d43c6bd7..b817e75289a97 100755 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -8,7 +8,6 @@ from pandas.util._decorators import Appender from pandas.core.dtypes.common import ( - is_float, is_integer, is_iterator, is_list_like, @@ -1547,18 +1546,13 @@ def _convert_to_indexer(self, key, axis: int, is_setter: bool = False): """ Much simpler as we only have to deal with our valid types. """ - labels = self.obj._get_axis(axis) - - # make need to convert a float key - if isinstance(key, slice): - labels._validate_positional_slice(key) - return key + return key - elif is_float(key): - labels._validate_indexer("positional", key, "iloc") - return key + def _get_setitem_indexer(self, key): + if isinstance(key, tuple): + if len(key) > self.ndim: + raise IndexingError("Too many indexers") - self._validate_key(key, axis) return key # ------------------------------------------------------------------- diff --git a/pandas/tests/indexing/test_floats.py b/pandas/tests/indexing/test_floats.py index 4d3f1b0539aee..d16a60e03b234 100644 --- a/pandas/tests/indexing/test_floats.py +++ b/pandas/tests/indexing/test_floats.py @@ -1,9 +1,17 @@ +import re + import numpy as np import pytest from pandas import DataFrame, Float64Index, Index, Int64Index, RangeIndex, Series import pandas._testing as tm +# We pass through the error message from numpy +iloc_msg = re.escape( + "only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) " + "and integer or boolean arrays are valid indices" +) + def gen_obj(klass, index): if klass is Series: @@ -62,11 +70,7 @@ def test_scalar_error(self, index_func): with pytest.raises(TypeError, match=msg): s.iloc[3.0] - msg = ( - f"cannot do positional indexing on {type(i).__name__} with these " - r"indexers \[3\.0\] of type float" - ) - with pytest.raises(TypeError, match=msg): + with pytest.raises(IndexError, match=iloc_msg): s.iloc[3.0] = 0 @pytest.mark.parametrize( @@ -133,12 +137,7 @@ def test_scalar_non_numeric(self, index_func, klass): assert 3.0 not in s # setting with a float fails with iloc - msg = ( - r"cannot do (label|positional) indexing " - fr"on {type(i).__name__} with these indexers \[3\.0\] of " - "type float" - ) - with pytest.raises(TypeError, match=msg): + with pytest.raises(IndexError, match=iloc_msg): s.iloc[3.0] = 0 # setting with an indexer @@ -333,12 +332,7 @@ def test_scalar_float(self, klass): with pytest.raises(TypeError, match=msg): s.iloc[3.0] - msg = ( - "cannot do positional indexing " - fr"on {Float64Index.__name__} with these indexers \[3\.0\] of " - "type float" - ) - with pytest.raises(TypeError, match=msg): + with pytest.raises(IndexError, match=iloc_msg): s2.iloc[3.0] = 0 @pytest.mark.parametrize( @@ -382,11 +376,7 @@ def test_slice_non_numeric(self, index_func, l, klass): idxr(s)[l] # setitem - msg = ( - "cannot do positional indexing " - fr"on {type(index).__name__} with these indexers \[(3|4)\.0\] of " - "type float" - ) + msg = "slice indices must be integers or None or have an __index__ method" with pytest.raises(TypeError, match=msg): s.iloc[l] = 0 @@ -396,7 +386,7 @@ def test_slice_non_numeric(self, index_func, l, klass): r"\[(3|4)(\.0)?\] " r"of type (float|int)" ) - for idxr in [lambda x: x.loc, lambda x: x.iloc, lambda x: x]: + for idxr in [lambda x: x.loc, lambda x: x]: with pytest.raises(TypeError, match=msg): idxr(s)[l] = 0 From 8a0e78f57123c6596335188ba52f367c08e4a222 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Wed, 26 Feb 2020 11:31:54 -0800 Subject: [PATCH 2/2] Let numpy validate tuple length --- pandas/core/indexing.py | 6 +----- pandas/tests/frame/indexing/test_indexing.py | 3 ++- pandas/tests/indexing/test_floats.py | 8 ++++---- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index cc1e64542cb29..69283bc58799e 100755 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -1502,11 +1502,7 @@ def _convert_to_indexer(self, key, axis: int, is_setter: bool = False): return key def _get_setitem_indexer(self, key): - if isinstance(key, tuple): - if len(key) > self.ndim: - # TODO: we could let this fall through if we are OK - # with having numpy raise IndexError("too many indices for array") - raise IndexingError("Too many indexers") + # GH#32257 Fall through to let numnpy do validation return key # ------------------------------------------------------------------- diff --git a/pandas/tests/frame/indexing/test_indexing.py b/pandas/tests/frame/indexing/test_indexing.py index 90e275044edf1..997414eceeb86 100644 --- a/pandas/tests/frame/indexing/test_indexing.py +++ b/pandas/tests/frame/indexing/test_indexing.py @@ -997,7 +997,8 @@ def test_getitem_setitem_fancy_exceptions(self, float_frame): with pytest.raises(IndexingError, match="Too many indexers"): ix[:, :, :] - with pytest.raises(IndexingError, match="Too many indexers"): + with pytest.raises(IndexError, match="too many indices for array"): + # GH#32257 we let numpy do validation, get their exception ix[:, :, :] = 1 def test_getitem_setitem_boolean_misaligned(self, float_frame): diff --git a/pandas/tests/indexing/test_floats.py b/pandas/tests/indexing/test_floats.py index 9e4b8d3dc8da2..a84e88cefbced 100644 --- a/pandas/tests/indexing/test_floats.py +++ b/pandas/tests/indexing/test_floats.py @@ -7,7 +7,7 @@ import pandas._testing as tm # We pass through the error message from numpy -iloc_msg = re.escape( +_slice_iloc_msg = re.escape( "only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) " "and integer or boolean arrays are valid indices" ) @@ -70,7 +70,7 @@ def test_scalar_error(self, index_func): with pytest.raises(TypeError, match=msg): s.iloc[3.0] - with pytest.raises(IndexError, match=iloc_msg): + with pytest.raises(IndexError, match=_slice_iloc_msg): s.iloc[3.0] = 0 @pytest.mark.parametrize( @@ -137,7 +137,7 @@ def test_scalar_non_numeric(self, index_func, klass): assert 3.0 not in s # setting with a float fails with iloc - with pytest.raises(IndexError, match=iloc_msg): + with pytest.raises(IndexError, match=_slice_iloc_msg): s.iloc[3.0] = 0 # setting with an indexer @@ -326,7 +326,7 @@ def test_scalar_float(self, klass): with pytest.raises(TypeError, match=msg): s.iloc[3.0] - with pytest.raises(IndexError, match=iloc_msg): + with pytest.raises(IndexError, match=_slice_iloc_msg): s2.iloc[3.0] = 0 @pytest.mark.parametrize(