From cd9b6a08fb50abe853e83fe0b064ff6dd8e6d2df Mon Sep 17 00:00:00 2001 From: arthurlw Date: Sat, 8 Mar 2025 19:30:42 -0800 Subject: [PATCH 1/5] __setitem__ raises NotImplemented when bool mask passed through iloc --- pandas/core/indexing.py | 12 ++++++++++++ pandas/tests/frame/indexing/test_getitem.py | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index bcb27d0320c91..62a0ccc89362c 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -1637,6 +1637,18 @@ def _has_valid_setitem_indexer(self, indexer) -> bool: "Consider using .loc with a DataFrame indexer for automatic alignment.", ) + # Check for Series boolean indexer + if com.is_bool_indexer(indexer) and hasattr(indexer, "index") and isinstance(indexer.index, Index): + if indexer.index.inferred_type == "integer": + raise NotImplementedError( + "iLocation based boolean " + "indexing on an integer type " + "is not available" + ) + raise ValueError( + "iLocation based boolean indexing cannot use an indexable as a mask" + ) + if not isinstance(indexer, tuple): indexer = _tuplify(self.ndim, indexer) diff --git a/pandas/tests/frame/indexing/test_getitem.py b/pandas/tests/frame/indexing/test_getitem.py index 25d6e06a4c675..7ccf1e8ae0c00 100644 --- a/pandas/tests/frame/indexing/test_getitem.py +++ b/pandas/tests/frame/indexing/test_getitem.py @@ -407,6 +407,19 @@ def test_getitem_frozenset_unique_in_column(self): expected = Series([1], name=frozenset(["KEY"])) tm.assert_series_equal(result, expected) + def test_series_boolean_indexer_iloc_consistency(self): + # GH#60994 - Test consistency between __getitem__ and __setitem__ for Series boolean indexers + ser = Series([0, 1, 2]) + mask = Series([True, False, False]) + + # __getitem__ should raise NotImplementedError + with pytest.raises(NotImplementedError, match="iLocation based boolean indexing on an integer type is not available"): + ser.iloc[mask] + + # __setitem__ should also raise NotImplementedError for consistency + with pytest.raises(NotImplementedError, match="iLocation based boolean indexing on an integer type is not available"): + ser.iloc[mask] = 10 + class TestGetitemSlice: def test_getitem_slice_float64(self, frame_or_series): From 0de32bab90efaf6c5c5a200d3e3e3cce178fc0a7 Mon Sep 17 00:00:00 2001 From: Arthur Laureus Wigo Date: Sun, 9 Mar 2025 03:45:25 +0000 Subject: [PATCH 2/5] adjust for precommit --- pandas/core/indexing.py | 6 +++++- pandas/tests/frame/indexing/test_getitem.py | 12 +++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 62a0ccc89362c..df74899528044 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -1638,7 +1638,11 @@ def _has_valid_setitem_indexer(self, indexer) -> bool: ) # Check for Series boolean indexer - if com.is_bool_indexer(indexer) and hasattr(indexer, "index") and isinstance(indexer.index, Index): + if ( + com.is_bool_indexer(indexer) + and hasattr(indexer, "index") + and isinstance(indexer.index, Index) + ): if indexer.index.inferred_type == "integer": raise NotImplementedError( "iLocation based boolean " diff --git a/pandas/tests/frame/indexing/test_getitem.py b/pandas/tests/frame/indexing/test_getitem.py index 7ccf1e8ae0c00..bbd219dff0942 100644 --- a/pandas/tests/frame/indexing/test_getitem.py +++ b/pandas/tests/frame/indexing/test_getitem.py @@ -408,16 +408,18 @@ def test_getitem_frozenset_unique_in_column(self): tm.assert_series_equal(result, expected) def test_series_boolean_indexer_iloc_consistency(self): - # GH#60994 - Test consistency between __getitem__ and __setitem__ for Series boolean indexers + # GH#60994 - Test consistency between __getitem__ and __setitem__ for Series + # boolean indexers ser = Series([0, 1, 2]) mask = Series([True, False, False]) - + # __getitem__ should raise NotImplementedError - with pytest.raises(NotImplementedError, match="iLocation based boolean indexing on an integer type is not available"): + msg = "iLocation based boolean indexing on an integer type is not available" + with pytest.raises(NotImplementedError, match=msg): ser.iloc[mask] - + # __setitem__ should also raise NotImplementedError for consistency - with pytest.raises(NotImplementedError, match="iLocation based boolean indexing on an integer type is not available"): + with pytest.raises(NotImplementedError, match=msg): ser.iloc[mask] = 10 From eb164641cb035cba16d042a85cf22a225a3c9baa Mon Sep 17 00:00:00 2001 From: Arthur Laureus Wigo <126365160+arthurlw@users.noreply.github.com> Date: Sat, 8 Mar 2025 19:51:59 -0800 Subject: [PATCH 3/5] whatsnew --- doc/source/whatsnew/v3.0.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index 4a6cf117fd196..971f8cb8c6938 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -698,6 +698,7 @@ Indexing - Bug in :meth:`DataFrame.loc` with inconsistent behavior of loc-set with 2 given indexes to Series (:issue:`59933`) - Bug in :meth:`MultiIndex.insert` when a new value inserted to a datetime-like level gets cast to ``NaT`` and fails indexing (:issue:`60388`) - Bug in printing :attr:`Index.names` and :attr:`MultiIndex.levels` would not escape single quotes (:issue:`60190`) +- Bug in :meth:`Series.iloc` with inconsistent behavior between ``__getitem__`` and ``__setitem__`` for Series boolean indexers (:issue:`60994`) Missing ^^^^^^^ From 37bb4c9c5f6330eea75336ee1522d7fd8211b500 Mon Sep 17 00:00:00 2001 From: Arthur Laureus Wigo <126365160+arthurlw@users.noreply.github.com> Date: Sat, 8 Mar 2025 20:02:33 -0800 Subject: [PATCH 4/5] sorted whatsnew --- doc/source/whatsnew/v3.0.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index 971f8cb8c6938..f7443e614d19a 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -697,8 +697,8 @@ Indexing - Bug in :meth:`DataFrame.from_records` throwing a ``ValueError`` when passed an empty list in ``index`` (:issue:`58594`) - Bug in :meth:`DataFrame.loc` with inconsistent behavior of loc-set with 2 given indexes to Series (:issue:`59933`) - Bug in :meth:`MultiIndex.insert` when a new value inserted to a datetime-like level gets cast to ``NaT`` and fails indexing (:issue:`60388`) -- Bug in printing :attr:`Index.names` and :attr:`MultiIndex.levels` would not escape single quotes (:issue:`60190`) - Bug in :meth:`Series.iloc` with inconsistent behavior between ``__getitem__`` and ``__setitem__`` for Series boolean indexers (:issue:`60994`) +- Bug in printing :attr:`Index.names` and :attr:`MultiIndex.levels` would not escape single quotes (:issue:`60190`) Missing ^^^^^^^ From 087e51cbd093376772c11962b0c1b24b422d9326 Mon Sep 17 00:00:00 2001 From: Arthur Laureus Wigo Date: Sun, 9 Mar 2025 23:12:20 +0000 Subject: [PATCH 5/5] added error capturing on reduce test --- pandas/tests/extension/base/reduce.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pandas/tests/extension/base/reduce.py b/pandas/tests/extension/base/reduce.py index 4b3431d938f96..5194fed431708 100644 --- a/pandas/tests/extension/base/reduce.py +++ b/pandas/tests/extension/base/reduce.py @@ -105,6 +105,11 @@ def test_reduce_series_numeric(self, data, all_numeric_reductions, skipna): msg = ( "[Cc]annot perform|Categorical is not ordered for operation|" "does not support operation|" + "unsupported operand type|" + "NotImplemented|" + "not supported between instances|" + "NotImplementedType|" + "iLocation based boolean" ) with pytest.raises(TypeError, match=msg):