diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 34a437ba40bd8..8918f488e4e04 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -1609,9 +1609,18 @@ def _validate_key(self, key, axis: AxisInt) -> None: if not is_numeric_dtype(arr.dtype): raise IndexError(f".iloc requires numeric indexers, got {arr}") - # check that the key does not exceed the maximum size of the index - if len(arr) and (arr.max() >= len_axis or arr.min() < -len_axis): - raise IndexError("positional indexers are out-of-bounds") + if len(arr): + # handle ExtensionArray using _reduce method else use numpy + if isinstance(arr.dtype, ExtensionDtype): + arr_max = arr._reduce("max") + arr_min = arr._reduce("min") + else: + arr_max = np.max(arr) + arr_min = np.min(arr) + + # check that the key does not exceed the maximum size + if arr_max >= len_axis or arr_min < -len_axis: + raise IndexError("positional indexers are out-of-bounds") else: raise ValueError(f"Can only index by location with a [{self._valid_types}]") diff --git a/pandas/tests/indexing/test_iloc.py b/pandas/tests/indexing/test_iloc.py index 3be69617cad43..71e7c581c2d17 100644 --- a/pandas/tests/indexing/test_iloc.py +++ b/pandas/tests/indexing/test_iloc.py @@ -1478,3 +1478,14 @@ def test_iloc_nullable_int64_size_1_nan(self): result = DataFrame({"a": ["test"], "b": [np.nan]}) with pytest.raises(TypeError, match="Invalid value"): result.loc[:, "b"] = result.loc[:, "b"].astype("Int64") + + def test_iloc_arrow_extension_array(self): + # GH#61311 + pytest.importorskip("pyarrow") + df = DataFrame({"a": [1, 2], "c": [0, 2], "d": ["c", "a"]}) + df_arrow = DataFrame( + {"a": [1, 2], "c": [0, 2], "d": ["c", "a"]} + ).convert_dtypes(dtype_backend="pyarrow") + expected = df.iloc[:, df["c"]] + result = df_arrow.iloc[:, df_arrow["c"]] + tm.assert_frame_equal(result, expected, check_dtype=False)