diff --git a/doc/source/whatsnew/v1.2.3.rst b/doc/source/whatsnew/v1.2.3.rst index d305024909703..41cea7fe125a1 100644 --- a/doc/source/whatsnew/v1.2.3.rst +++ b/doc/source/whatsnew/v1.2.3.rst @@ -16,6 +16,7 @@ Fixed regressions ~~~~~~~~~~~~~~~~~ - Fixed regression in :meth:`~DataFrame.to_excel` raising ``KeyError`` when giving duplicate columns with ``columns`` attribute (:issue:`39695`) +- Fixed regression in :class:`IntegerArray` unary ops propagating mask on assignment (:issue:`39943`) - Fixed regression in :meth:`DataFrame.__setitem__` not aligning :class:`DataFrame` on right-hand side for boolean indexer (:issue:`39931`) .. --------------------------------------------------------------------------- diff --git a/pandas/core/arrays/integer.py b/pandas/core/arrays/integer.py index fa427e94fe08f..96ac0dad18e65 100644 --- a/pandas/core/arrays/integer.py +++ b/pandas/core/arrays/integer.py @@ -348,13 +348,13 @@ def __init__(self, values: np.ndarray, mask: np.ndarray, copy: bool = False): super().__init__(values, mask, copy=copy) def __neg__(self): - return type(self)(-self._data, self._mask) + return type(self)(-self._data, self._mask.copy()) def __pos__(self): return self def __abs__(self): - return type(self)(np.abs(self._data), self._mask) + return type(self)(np.abs(self._data), self._mask.copy()) @classmethod def _from_sequence( diff --git a/pandas/core/arrays/masked.py b/pandas/core/arrays/masked.py index caed932cd7857..d47abfe226593 100644 --- a/pandas/core/arrays/masked.py +++ b/pandas/core/arrays/masked.py @@ -142,7 +142,7 @@ def __len__(self) -> int: return len(self._data) def __invert__(self: BaseMaskedArrayT) -> BaseMaskedArrayT: - return type(self)(~self._data, self._mask) + return type(self)(~self._data, self._mask.copy()) def to_numpy( self, dtype=None, copy: bool = False, na_value: Scalar = lib.no_default diff --git a/pandas/tests/arrays/masked/test_arithmetic.py b/pandas/tests/arrays/masked/test_arithmetic.py index 1d2833c5da276..148b7092abb56 100644 --- a/pandas/tests/arrays/masked/test_arithmetic.py +++ b/pandas/tests/arrays/masked/test_arithmetic.py @@ -159,3 +159,16 @@ def test_error_len_mismatch(data, all_arithmetic_operators): s = pd.Series(data) with pytest.raises(ValueError, match="Lengths must match"): op(s, other) + + +@pytest.mark.parametrize("op", ["__neg__", "__abs__", "__invert__"]) +@pytest.mark.parametrize( + "values, dtype", [([1, 2, 3], "Int64"), ([True, False, True], "boolean")] +) +def test_unary_op_does_not_propagate_mask(op, values, dtype): + # https://github.com/pandas-dev/pandas/issues/39943 + s = pd.Series(values, dtype=dtype) + result = getattr(s, op)() + expected = result.copy(deep=True) + s[0] = None + tm.assert_series_equal(result, expected)