Skip to content

Commit 7f78a64

Browse files
committed
Raise for NaN
1 parent 373aaab commit 7f78a64

File tree

2 files changed

+47
-32
lines changed

2 files changed

+47
-32
lines changed

pandas/core/arrays/boolean.py

+36-29
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ def __getitem__(self, item):
286286

287287
def _coerce_to_ndarray(self, force_bool: bool = False):
288288
"""
289-
Coerce to an ndarary of object dtype or bool dtype (if force_bool=True).
289+
Coerce to an ndarray of object dtype or bool dtype (if force_bool=True).
290290
291291
Parameters
292292
----------
@@ -743,9 +743,9 @@ def boolean_arithmetic_method(self, other):
743743

744744

745745
def kleene_or(
746-
left: Union[bool, np.nan, np.ndarray],
747-
right: Union[bool, np.nan, np.ndarary],
748-
left_mask: Optional[np.ndarary],
746+
left: Union[bool, np.ndarray],
747+
right: Union[bool, np.ndarray],
748+
left_mask: Optional[np.ndarray],
749749
right_mask: Optional[np.ndarray],
750750
):
751751
"""
@@ -772,8 +772,7 @@ def kleene_or(
772772
if left_mask is None:
773773
return kleene_or(right, left, right_mask, left_mask)
774774

775-
assert left_mask is not None
776-
right_is_scalar = right_mask is None
775+
raise_for_nan(right, method="or")
777776

778777
mask = left_mask
779778

@@ -783,11 +782,11 @@ def kleene_or(
783782
mask = mask.copy()
784783

785784
# handle scalars:
786-
if right_is_scalar and np.isnan(right): # TODO(pd.NA): change to NA
787-
result = left.copy()
788-
mask = left_mask.copy()
789-
mask[~result] = True
790-
return result, mask
785+
# if right_is_scalar and right is libmissing.NA:
786+
# result = left.copy()
787+
# mask = left_mask.copy()
788+
# mask[~result] = True
789+
# return result, mask
791790

792791
# XXX: verify that this doesn't assume masked values are False!
793792
result = left | right
@@ -798,9 +797,9 @@ def kleene_or(
798797

799798

800799
def kleene_xor(
801-
left: Union[bool, np.nan, np.ndarray],
802-
right: Union[bool, np.nan, np.ndarary],
803-
left_mask: Optional[np.ndarary],
800+
left: Union[bool, np.ndarray],
801+
right: Union[bool, np.ndarray],
802+
left_mask: Optional[np.ndarray],
804803
right_mask: Optional[np.ndarray],
805804
):
806805
"""
@@ -826,29 +825,30 @@ def kleene_xor(
826825
if left_mask is None:
827826
return kleene_xor(right, left, right_mask, left_mask)
828827

829-
# Re-use or, and update with adustments.
828+
raise_for_nan(right, method="xor")
829+
# Re-use or, and update with adjustments.
830830
result, mask = kleene_or(left, right, left_mask, right_mask)
831831

832-
# TODO(pd.NA): change to pd.NA
833-
if lib.is_scalar(right) and right is np.nan:
834-
# True | NA == True
835-
# True ^ NA == NA
836-
mask[result] = True
837-
else:
838-
# XXX: verify that this doesn't assume masked values are False!
839-
result[left & right] = False
840-
mask[right & left_mask] = True
841-
if right_mask is not None:
842-
mask[left & right_mask] = True
832+
# # TODO(pd.NA): change to pd.NA
833+
# if lib.is_scalar(right) and right is libmissing.NA:
834+
# # True | NA == True
835+
# # True ^ NA == NA
836+
# mask[result] = True
837+
838+
# XXX: verify that this doesn't assume masked values are False!
839+
result[left & right] = False
840+
mask[right & left_mask] = True
841+
if right_mask is not None:
842+
mask[left & right_mask] = True
843843

844844
result[mask] = False
845845
return result, mask
846846

847847

848848
def kleene_and(
849-
left: Union[bool, np.nan, np.ndarray],
850-
right: Union[bool, np.nan, np.ndarary],
851-
left_mask: Optional[np.ndarary],
849+
left: Union[bool, np.ndarray],
850+
right: Union[bool, np.ndarray],
851+
left_mask: Optional[np.ndarray],
852852
right_mask: Optional[np.ndarray],
853853
):
854854
"""
@@ -871,6 +871,7 @@ def kleene_and(
871871
if left_mask is None:
872872
return kleene_and(right, left, right_mask, left_mask)
873873

874+
raise_for_nan(right, method="and")
874875
mask = left_mask
875876

876877
if right_mask is not None:
@@ -882,6 +883,7 @@ def kleene_and(
882883
result = left.copy()
883884
mask = left_mask.copy()
884885
if np.isnan(right):
886+
# TODO(pd.NA): change to NA
885887
mask[result] = True
886888
else:
887889
result = result & right # already copied.
@@ -898,6 +900,11 @@ def kleene_and(
898900
return result, mask
899901

900902

903+
def raise_for_nan(value, method):
904+
if lib.is_scalar(value) and isinstance(value, float) and np.isnan(value):
905+
raise ValueError(f"Cannot perform logical '{method}' with NaN")
906+
907+
901908
BooleanArray._add_logical_ops()
902909
BooleanArray._add_comparison_ops()
903910
BooleanArray._add_arithmetic_ops()

pandas/tests/arrays/test_boolean.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,14 @@ def test_logical_length_mismatch_raises(self, all_logical_operators):
374374
with pytest.raises(ValueError, match=msg):
375375
getattr(a, op_name)(pd.array([True, False], dtype="boolean"))
376376

377+
def test_logical_nan_raises(self, all_logical_operators):
378+
op_name = all_logical_operators
379+
a = pd.array([True, False, None], dtype="boolean")
380+
msg = ""
381+
382+
with pytest.raises(ValueError, match=msg):
383+
getattr(a, op_name)(np.nan)
384+
377385
def test_kleene_or(self):
378386
# A clear test of behavior.
379387
a = pd.array([True] * 3 + [False] * 3 + [None] * 3, dtype="boolean")
@@ -390,7 +398,7 @@ def test_kleene_or(self):
390398
@pytest.mark.parametrize(
391399
"other, expected",
392400
[
393-
(np.nan, [True, None, None]),
401+
# (pd.NA, [True, None, None]),
394402
(True, [True, True, True]),
395403
(False, [True, False, None]),
396404
],
@@ -421,7 +429,7 @@ def test_kleene_and(self):
421429
@pytest.mark.parametrize(
422430
"other, expected",
423431
[
424-
(np.nan, [None, False, None]),
432+
# (pd.NA, [None, False, None]),
425433
(True, [True, False, None]),
426434
(False, [False, False, False]),
427435
],
@@ -450,7 +458,7 @@ def test_kleene_xor(self):
450458
@pytest.mark.parametrize(
451459
"other, expected",
452460
[
453-
(np.nan, [None, None, None]),
461+
# (pd.NA, [None, None, None]),
454462
(True, [False, True, None]),
455463
(False, [True, False, None]),
456464
],

0 commit comments

Comments
 (0)