From 281dcc3fcf6c84a5092316a17cd46c574435d878 Mon Sep 17 00:00:00 2001 From: Shrey Dixit <31824249+ShreyDixit@users.noreply.github.com> Date: Thu, 27 May 2021 20:13:51 +0530 Subject: [PATCH] Deprecate non-keyword arguments in mask (#41580) --- doc/source/whatsnew/v1.3.0.rst | 1 + pandas/core/frame.py | 15 +++++++++++++++ pandas/core/generic.py | 2 +- pandas/core/series.py | 15 +++++++++++++++ pandas/tests/frame/indexing/test_mask.py | 13 +++++++++++++ pandas/tests/series/indexing/test_mask.py | 14 ++++++++++++++ 6 files changed, 59 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index 8d51fac53b642c..503bbee3963e28 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -680,6 +680,7 @@ Deprecations - Deprecated behavior of :meth:`DatetimeIndex.union` with mixed timezones; in a future version both will be cast to UTC instead of object dtype (:issue:`39328`) - Deprecated using ``usecols`` with out of bounds indices for ``read_csv`` with ``engine="c"`` (:issue:`25623`) - Deprecated passing arguments as positional in :meth:`Index.set_names` and :meth:`MultiIndex.set_names` (except for ``names``) (:issue:`41485`) +- Deprecated passing arguments (apart from ``cond`` and ``other``) as positional in :meth:`DataFrame.mask` and :meth:`Series.mask` (:issue:`41485`) - Deprecated passing arguments as positional in :meth:`DataFrame.clip` and :meth:`Series.clip` (other than ``"upper"`` and ``"lower"``) (:issue:`41485`) - Deprecated special treatment of lists with first element a Categorical in the :class:`DataFrame` constructor; pass as ``pd.DataFrame({col: categorical, ...})`` instead (:issue:`38845`) - Deprecated passing arguments as positional (except for ``"method"``) in :meth:`DataFrame.interpolate` and :meth:`Series.interpolate` (:issue:`41485`) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 1d45581fa50470..6e71cb49596c8f 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -10720,6 +10720,21 @@ def where( ): return super().where(cond, other, inplace, axis, level, errors, try_cast) + @deprecate_nonkeyword_arguments( + version=None, allowed_args=["self", "cond", "other"] + ) + def mask( + self, + cond, + other=np.nan, + inplace=False, + axis=None, + level=None, + errors="raise", + try_cast=lib.no_default, + ): + return super().mask(cond, other, inplace, axis, level, errors, try_cast) + DataFrame._add_numeric_operations() diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 3e6642d3b1a724..49dc71954fd8f5 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -9062,7 +9062,7 @@ def mask( "try_cast keyword is deprecated and will be removed in a " "future version", FutureWarning, - stacklevel=2, + stacklevel=4, ) # see gh-21891 diff --git a/pandas/core/series.py b/pandas/core/series.py index 871b7fb4f9f956..2f45a2adbdec73 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -5366,6 +5366,21 @@ def where( ): return super().where(cond, other, inplace, axis, level, errors, try_cast) + @deprecate_nonkeyword_arguments( + version=None, allowed_args=["self", "cond", "other"] + ) + def mask( + self, + cond, + other=np.nan, + inplace=False, + axis=None, + level=None, + errors="raise", + try_cast=lib.no_default, + ): + return super().mask(cond, other, inplace, axis, level, errors, try_cast) + # ---------------------------------------------------------------------- # Add index _AXIS_ORDERS = ["index"] diff --git a/pandas/tests/frame/indexing/test_mask.py b/pandas/tests/frame/indexing/test_mask.py index 364475428e529b..ac80426883dd52 100644 --- a/pandas/tests/frame/indexing/test_mask.py +++ b/pandas/tests/frame/indexing/test_mask.py @@ -90,6 +90,19 @@ def test_mask_dtype_bool_conversion(self): result = bools.mask(mask) tm.assert_frame_equal(result, expected) + def test_mask_pos_args_deprecation(self): + # https://github.com/pandas-dev/pandas/issues/41485 + df = DataFrame({"a": range(5)}) + expected = DataFrame({"a": [-1, 1, -1, 3, -1]}) + cond = df % 2 == 0 + msg = ( + r"In a future version of pandas all arguments of DataFrame.mask except for " + r"the arguments 'cond' and 'other' will be keyword-only" + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + result = df.mask(cond, -1, False) + tm.assert_frame_equal(result, expected) + def test_mask_try_cast_deprecated(frame_or_series): diff --git a/pandas/tests/series/indexing/test_mask.py b/pandas/tests/series/indexing/test_mask.py index a4dda3a5c0c5bf..30a9d925ed7e5a 100644 --- a/pandas/tests/series/indexing/test_mask.py +++ b/pandas/tests/series/indexing/test_mask.py @@ -86,3 +86,17 @@ def test_mask_stringdtype(): dtype=StringDtype(), ) tm.assert_series_equal(result, expected) + + +def test_mask_pos_args_deprecation(): + # https://github.com/pandas-dev/pandas/issues/41485 + s = Series(range(5)) + expected = Series([-1, 1, -1, 3, -1]) + cond = s % 2 == 0 + msg = ( + r"In a future version of pandas all arguments of Series.mask except for " + r"the arguments 'cond' and 'other' will be keyword-only" + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + result = s.mask(cond, -1, False) + tm.assert_series_equal(result, expected)