Skip to content

Commit e4f37e0

Browse files
jbrockmendelroberthdevries
authored andcommitted
PERF: pass through to numpy validation for iloc setitem (pandas-dev#32257)
1 parent ac0ba68 commit e4f37e0

File tree

3 files changed

+22
-37
lines changed

3 files changed

+22
-37
lines changed

pandas/core/indexing.py

+3-12
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from pandas.util._decorators import Appender
99

1010
from pandas.core.dtypes.common import (
11-
is_float,
1211
is_integer,
1312
is_iterator,
1413
is_list_like,
@@ -1500,18 +1499,10 @@ def _convert_to_indexer(self, key, axis: int, is_setter: bool = False):
15001499
"""
15011500
Much simpler as we only have to deal with our valid types.
15021501
"""
1503-
labels = self.obj._get_axis(axis)
1504-
1505-
# make need to convert a float key
1506-
if isinstance(key, slice):
1507-
labels._validate_positional_slice(key)
1508-
return key
1509-
1510-
elif is_float(key):
1511-
# _validate_indexer call will always raise
1512-
labels._validate_indexer("positional", key, "iloc")
1502+
return key
15131503

1514-
self._validate_key(key, axis)
1504+
def _get_setitem_indexer(self, key):
1505+
# GH#32257 Fall through to let numnpy do validation
15151506
return key
15161507

15171508
# -------------------------------------------------------------------

pandas/tests/frame/indexing/test_indexing.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727

2828
from pandas.tseries.offsets import BDay
2929

30+
# We pass through a TypeError raised by numpy
31+
_slice_msg = "slice indices must be integers or None or have an __index__ method"
32+
3033

3134
class TestGet:
3235
def test_get(self, float_frame):
@@ -994,7 +997,8 @@ def test_getitem_setitem_fancy_exceptions(self, float_frame):
994997
with pytest.raises(IndexingError, match="Too many indexers"):
995998
ix[:, :, :]
996999

997-
with pytest.raises(IndexingError, match="Too many indexers"):
1000+
with pytest.raises(IndexError, match="too many indices for array"):
1001+
# GH#32257 we let numpy do validation, get their exception
9981002
ix[:, :, :] = 1
9991003

10001004
def test_getitem_setitem_boolean_misaligned(self, float_frame):
@@ -1073,7 +1077,7 @@ def test_getitem_setitem_float_labels(self):
10731077

10741078
cp = df.copy()
10751079

1076-
with pytest.raises(TypeError, match=msg):
1080+
with pytest.raises(TypeError, match=_slice_msg):
10771081
cp.iloc[1.0:5] = 0
10781082

10791083
with pytest.raises(TypeError, match=msg):

pandas/tests/indexing/test_floats.py

+13-23
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
1+
import re
2+
13
import numpy as np
24
import pytest
35

46
from pandas import DataFrame, Float64Index, Index, Int64Index, RangeIndex, Series
57
import pandas._testing as tm
68

9+
# We pass through the error message from numpy
10+
_slice_iloc_msg = re.escape(
11+
"only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) "
12+
"and integer or boolean arrays are valid indices"
13+
)
14+
715

816
def gen_obj(klass, index):
917
if klass is Series:
@@ -62,11 +70,7 @@ def test_scalar_error(self, index_func):
6270
with pytest.raises(TypeError, match=msg):
6371
s.iloc[3.0]
6472

65-
msg = (
66-
f"cannot do positional indexing on {type(i).__name__} with these "
67-
r"indexers \[3\.0\] of type float"
68-
)
69-
with pytest.raises(TypeError, match=msg):
73+
with pytest.raises(IndexError, match=_slice_iloc_msg):
7074
s.iloc[3.0] = 0
7175

7276
@pytest.mark.parametrize(
@@ -133,12 +137,7 @@ def test_scalar_non_numeric(self, index_func, klass):
133137
assert 3.0 not in s
134138

135139
# setting with a float fails with iloc
136-
msg = (
137-
r"cannot do (label|positional) indexing "
138-
fr"on {type(i).__name__} with these indexers \[3\.0\] of "
139-
"type float"
140-
)
141-
with pytest.raises(TypeError, match=msg):
140+
with pytest.raises(IndexError, match=_slice_iloc_msg):
142141
s.iloc[3.0] = 0
143142

144143
# setting with an indexer
@@ -327,12 +326,7 @@ def test_scalar_float(self, klass):
327326
with pytest.raises(TypeError, match=msg):
328327
s.iloc[3.0]
329328

330-
msg = (
331-
"cannot do positional indexing "
332-
fr"on {Float64Index.__name__} with these indexers \[3\.0\] of "
333-
"type float"
334-
)
335-
with pytest.raises(TypeError, match=msg):
329+
with pytest.raises(IndexError, match=_slice_iloc_msg):
336330
s2.iloc[3.0] = 0
337331

338332
@pytest.mark.parametrize(
@@ -376,11 +370,7 @@ def test_slice_non_numeric(self, index_func, l, klass):
376370
idxr(s)[l]
377371

378372
# setitem
379-
msg = (
380-
"cannot do positional indexing "
381-
fr"on {type(index).__name__} with these indexers \[(3|4)\.0\] of "
382-
"type float"
383-
)
373+
msg = "slice indices must be integers or None or have an __index__ method"
384374
with pytest.raises(TypeError, match=msg):
385375
s.iloc[l] = 0
386376

@@ -390,7 +380,7 @@ def test_slice_non_numeric(self, index_func, l, klass):
390380
r"\[(3|4)(\.0)?\] "
391381
r"of type (float|int)"
392382
)
393-
for idxr in [lambda x: x.loc, lambda x: x.iloc, lambda x: x]:
383+
for idxr in [lambda x: x.loc, lambda x: x]:
394384
with pytest.raises(TypeError, match=msg):
395385
idxr(s)[l] = 0
396386

0 commit comments

Comments
 (0)