Skip to content

Commit 316c47c

Browse files
jbrockmendelyehoshuadimarsky
authored andcommitted
BUG: Series[bool].__setitem__(BooleanArray) (pandas-dev#45462)
1 parent 8b5d431 commit 316c47c

File tree

3 files changed

+23
-7
lines changed

3 files changed

+23
-7
lines changed

doc/source/whatsnew/v1.5.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ Indexing
219219
- Bug in :meth:`DataFrame.iloc` where indexing a single row on a :class:`DataFrame` with a single ExtensionDtype column gave a copy instead of a view on the underlying data (:issue:`45241`)
220220
- Bug in :meth:`Series.__setitem__` with a non-integer :class:`Index` when using an integer key to set a value that cannot be set inplace where a ``ValueError`` was raised insead of casting to a common dtype (:issue:`45070`)
221221
- Bug when setting a value too large for a :class:`Series` dtype failing to coerce to a common type (:issue:`26049`, :issue:`32878`)
222+
- Bug in :meth:`Series.__setitem__` when setting ``boolean`` dtype values containing ``NA`` incorrectly raising instead of casting to ``boolean`` dtype (:issue:`45462`)
222223
- Bug in :meth:`Series.__setitem__` where setting :attr:`NA` into a numeric-dtpye :class:`Series` would incorrectly upcast to object-dtype rather than treating the value as ``np.nan`` (:issue:`44199`)
223224
-
224225

pandas/core/dtypes/cast.py

+8-7
Original file line numberDiff line numberDiff line change
@@ -1997,9 +1997,7 @@ def np_can_hold_element(dtype: np.dtype, element: Any) -> Any:
19971997
elif not isinstance(tipo, np.dtype):
19981998
# i.e. nullable IntegerDtype; we can put this into an ndarray
19991999
# losslessly iff it has no NAs
2000-
hasnas = element._mask.any()
2001-
# TODO: don't rely on implementation detail
2002-
if hasnas:
2000+
if element._hasna:
20032001
raise ValueError
20042002
return element
20052003

@@ -2016,9 +2014,7 @@ def np_can_hold_element(dtype: np.dtype, element: Any) -> Any:
20162014
elif not isinstance(tipo, np.dtype):
20172015
# i.e. nullable IntegerDtype or FloatingDtype;
20182016
# we can put this into an ndarray losslessly iff it has no NAs
2019-
hasnas = element._mask.any()
2020-
# TODO: don't rely on implementation detail
2021-
if hasnas:
2017+
if element._hasna:
20222018
raise ValueError
20232019
return element
20242020
return element
@@ -2047,7 +2043,12 @@ def np_can_hold_element(dtype: np.dtype, element: Any) -> Any:
20472043

20482044
elif dtype.kind == "b":
20492045
if tipo is not None:
2050-
if tipo.kind == "b": # FIXME: wrong with BooleanArray?
2046+
if tipo.kind == "b":
2047+
if not isinstance(tipo, np.dtype):
2048+
# i.e. we have a BooleanArray
2049+
if element._hasna:
2050+
# i.e. there are pd.NA elements
2051+
raise ValueError
20512052
return element
20522053
raise ValueError
20532054
if lib.is_bool(element):

pandas/tests/series/indexing/test_setitem.py

+14
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
Series,
2222
Timedelta,
2323
Timestamp,
24+
array,
2425
concat,
2526
date_range,
2627
period_range,
@@ -573,6 +574,19 @@ def test_setitem_non_bool_into_bool(self, val, indexer_sli, unique):
573574
expected = Series([val, val], dtype=object, index=[1, 1])
574575
tm.assert_series_equal(ser, expected)
575576

577+
def test_setitem_boolean_array_into_npbool(self):
578+
# GH#45462
579+
ser = Series([True, False, True])
580+
values = ser._values
581+
arr = array([True, False, None])
582+
583+
ser[:2] = arr[:2] # no NAs -> can set inplace
584+
assert ser._values is values
585+
586+
ser[1:] = arr[1:] # has an NA -> cast to boolean dtype
587+
expected = Series(arr)
588+
tm.assert_series_equal(ser, expected)
589+
576590

577591
class SetitemCastingEquivalents:
578592
"""

0 commit comments

Comments
 (0)