From a97bfe975cd481842559d1792c5141e161032cd0 Mon Sep 17 00:00:00 2001 From: Matthew Zeitlin Date: Sun, 18 Apr 2021 13:43:05 -0400 Subject: [PATCH 1/3] BUG: isna not returning copy for MaskedArray --- pandas/core/arrays/masked.py | 2 +- pandas/tests/extension/base/missing.py | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/pandas/core/arrays/masked.py b/pandas/core/arrays/masked.py index 93de1cd91d625..11f9f645920ec 100644 --- a/pandas/core/arrays/masked.py +++ b/pandas/core/arrays/masked.py @@ -352,7 +352,7 @@ def _hasna(self) -> bool: return self._mask.any() # type: ignore[return-value] def isna(self) -> np.ndarray: - return self._mask + return self._mask.copy() @property def _na_value(self): diff --git a/pandas/tests/extension/base/missing.py b/pandas/tests/extension/base/missing.py index c501694a7c2d5..ebe21bd70f374 100644 --- a/pandas/tests/extension/base/missing.py +++ b/pandas/tests/extension/base/missing.py @@ -1,8 +1,9 @@ import numpy as np - +import pytest import pandas as pd import pandas._testing as tm from pandas.tests.extension.base.base import BaseExtensionTests +from pandas.api.types import is_sparse class BaseMissingTests(BaseExtensionTests): @@ -21,6 +22,17 @@ def test_isna(self, data_missing): expected = pd.Series([], dtype=bool) self.assert_series_equal(result, expected) + @pytest.mark.parametrize("na_func", ["isna", "notna"]) + def test_isna_returns_copy(self, data_missing, na_func): + result = pd.Series(data_missing) + expected = result.copy() + mask = getattr(result, na_func)() + if is_sparse(mask): + mask = np.array(mask) + + mask[:] = True + self.assert_series_equal(result, expected) + def test_dropna_array(self, data_missing): result = data_missing.dropna() expected = data_missing[[1]] From 799133b55c64b4a5aecef548fa6edf8bc041ed51 Mon Sep 17 00:00:00 2001 From: Matthew Zeitlin Date: Sun, 18 Apr 2021 13:43:46 -0400 Subject: [PATCH 2/3] precommit fixup --- pandas/tests/extension/base/missing.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/tests/extension/base/missing.py b/pandas/tests/extension/base/missing.py index ebe21bd70f374..3d43dc47b5280 100644 --- a/pandas/tests/extension/base/missing.py +++ b/pandas/tests/extension/base/missing.py @@ -1,9 +1,10 @@ import numpy as np import pytest + import pandas as pd import pandas._testing as tm -from pandas.tests.extension.base.base import BaseExtensionTests from pandas.api.types import is_sparse +from pandas.tests.extension.base.base import BaseExtensionTests class BaseMissingTests(BaseExtensionTests): From b4d807711d187e4cf71689b77860f92568a6f828 Mon Sep 17 00:00:00 2001 From: Matthew Zeitlin Date: Sun, 18 Apr 2021 13:49:10 -0400 Subject: [PATCH 3/3] Add whatsnew --- doc/source/whatsnew/v1.3.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index 85d9acff353be..1a11fffbf6b4e 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -749,6 +749,7 @@ Missing - Bug in :class:`Grouper` now correctly propagates ``dropna`` argument and :meth:`DataFrameGroupBy.transform` now correctly handles missing values for ``dropna=True`` (:issue:`35612`) - Bug in :func:`isna`, and :meth:`Series.isna`, :meth:`Index.isna`, :meth:`DataFrame.isna` (and the corresponding ``notna`` functions) not recognizing ``Decimal("NaN")`` objects (:issue:`39409`) - Bug in :meth:`DataFrame.fillna` not accepting dictionary for ``downcast`` keyword (:issue:`40809`) +- Bug in :func:`isna` not returning a copy of the mask for nullable types, causing any subsequent mask modification to change the original array (:issue:`40935`) MultiIndex ^^^^^^^^^^