@@ -184,6 +184,9 @@ class BooleanArray(ExtensionArray, ExtensionOpsMixin):
184
184
represented by 2 numpy arrays: a boolean array with the data and
185
185
a boolean array with the mask (True indicating missing).
186
186
187
+ BooleanArray implements Kleene logic (sometimes called three-value
188
+ logic) for logical operations. See :ref:`boolean.kleene` for more.
189
+
187
190
To construct an BooleanArray from generic array-like input, use
188
191
:func:`pandas.array` specifying ``dtype="boolean"`` (see examples
189
192
below).
@@ -283,7 +286,7 @@ def __getitem__(self, item):
283
286
284
287
def _coerce_to_ndarray (self , dtype = None , na_value : "Scalar" = libmissing .NA ):
285
288
"""
286
- 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).
287
290
288
291
Parameters
289
292
----------
@@ -565,33 +568,40 @@ def logical_method(self, other):
565
568
# Rely on pandas to unbox and dispatch to us.
566
569
return NotImplemented
567
570
571
+ assert op .__name__ in {"or_" , "ror_" , "and_" , "rand_" , "xor" , "rxor" }
568
572
other = lib .item_from_zerodim (other )
573
+ other_is_booleanarray = isinstance (other , BooleanArray )
574
+ other_is_scalar = lib .is_scalar (other )
569
575
mask = None
570
576
571
- if isinstance ( other , BooleanArray ) :
577
+ if other_is_booleanarray :
572
578
other , mask = other ._data , other ._mask
573
579
elif is_list_like (other ):
574
580
other = np .asarray (other , dtype = "bool" )
575
581
if other .ndim > 1 :
576
582
raise NotImplementedError (
577
583
"can only perform ops with 1-d structures"
578
584
)
579
- if len (self ) != len (other ):
580
- raise ValueError ("Lengths must match to compare" )
581
585
other , mask = coerce_to_array (other , copy = False )
586
+ elif isinstance (other , np .bool_ ):
587
+ other = other .item ()
588
+
589
+ if other_is_scalar and not (other is libmissing .NA or lib .is_bool (other )):
590
+ raise TypeError (
591
+ "'other' should be pandas.NA or a bool. Got {} instead." .format (
592
+ type (other ).__name__
593
+ )
594
+ )
582
595
583
- # numpy will show a DeprecationWarning on invalid elementwise
584
- # comparisons, this will raise in the future
585
- with warnings .catch_warnings ():
586
- warnings .filterwarnings ("ignore" , "elementwise" , FutureWarning )
587
- with np .errstate (all = "ignore" ):
588
- result = op (self ._data , other )
596
+ if not other_is_scalar and len (self ) != len (other ):
597
+ raise ValueError ("Lengths must match to compare" )
589
598
590
- # nans propagate
591
- if mask is None :
592
- mask = self ._mask
593
- else :
594
- mask = self ._mask | mask
599
+ if op .__name__ in {"or_" , "ror_" }:
600
+ result , mask = ops .kleene_or (self ._data , other , self ._mask , mask )
601
+ elif op .__name__ in {"and_" , "rand_" }:
602
+ result , mask = ops .kleene_and (self ._data , other , self ._mask , mask )
603
+ elif op .__name__ in {"xor" , "rxor" }:
604
+ result , mask = ops .kleene_xor (self ._data , other , self ._mask , mask )
595
605
596
606
return BooleanArray (result , mask )
597
607
0 commit comments