From f126f919376083f8ae9c9b49ac95b1dffd5d1172 Mon Sep 17 00:00:00 2001 From: Brock Date: Thu, 3 Jul 2025 10:37:22 -0700 Subject: [PATCH] BUG: NA.__and__, __or__, __xor__ with np.bool_ objects --- doc/source/whatsnew/v3.0.0.rst | 1 + pandas/_libs/missing.pyx | 10 +++++++++- pandas/tests/scalar/test_na_scalar.py | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index 94e375615d122..4154942f92907 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -762,6 +762,7 @@ Indexing Missing ^^^^^^^ - Bug in :meth:`DataFrame.fillna` and :meth:`Series.fillna` that would ignore the ``limit`` argument on :class:`.ExtensionArray` dtypes (:issue:`58001`) +- Bug in :meth:`NA.__and__`, :meth:`NA.__or__` and :meth:`NA.__xor__` when operating with ``np.bool_`` objects (:issue:`58427`) - MultiIndex diff --git a/pandas/_libs/missing.pyx b/pandas/_libs/missing.pyx index 390a527c22bbb..c7f905c4d0be0 100644 --- a/pandas/_libs/missing.pyx +++ b/pandas/_libs/missing.pyx @@ -471,6 +471,10 @@ class NAType(C_NAType): return False elif other is True or other is C_NA: return NA + elif util.is_bool_object(other): + if not other: + return False + return NA return NotImplemented __rand__ = __and__ @@ -480,12 +484,16 @@ class NAType(C_NAType): return True elif other is False or other is C_NA: return NA + elif util.is_bool_object(other): + if not other: + return NA + return True return NotImplemented __ror__ = __or__ def __xor__(self, other): - if other is False or other is True or other is C_NA: + if util.is_bool_object(other) or other is C_NA: return NA return NotImplemented diff --git a/pandas/tests/scalar/test_na_scalar.py b/pandas/tests/scalar/test_na_scalar.py index 287b7557f50f9..d2bc8f521d7bb 100644 --- a/pandas/tests/scalar/test_na_scalar.py +++ b/pandas/tests/scalar/test_na_scalar.py @@ -167,6 +167,12 @@ def test_logical_and(): assert False & NA is False assert NA & NA is NA + # GH#58427 + assert NA & np.bool_(True) is NA + assert np.bool_(True) & NA is NA + assert NA & np.bool_(False) is False + assert np.bool_(False) & NA is False + msg = "unsupported operand type" with pytest.raises(TypeError, match=msg): NA & 5 @@ -179,6 +185,12 @@ def test_logical_or(): assert False | NA is NA assert NA | NA is NA + # GH#58427 + assert NA | np.bool_(True) is True + assert np.bool_(True) | NA is True + assert NA | np.bool_(False) is NA + assert np.bool_(False) | NA is NA + msg = "unsupported operand type" with pytest.raises(TypeError, match=msg): NA | 5 @@ -191,6 +203,12 @@ def test_logical_xor(): assert False ^ NA is NA assert NA ^ NA is NA + # GH#58427 + assert NA ^ np.bool_(True) is NA + assert np.bool_(True) ^ NA is NA + assert NA ^ np.bool_(False) is NA + assert np.bool_(False) ^ NA is NA + msg = "unsupported operand type" with pytest.raises(TypeError, match=msg): NA ^ 5