From eba9499d781e9e12b0c201345cce2615d059e46b Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Mon, 26 Sep 2022 15:34:16 -0700 Subject: [PATCH 1/6] REGR: fix df.apply with keyword non-zero axis Fixes #48656. Builds on top of #48693. An alternative fix could be to use `inspect.signature`, since `inspect.signature` defaults to following wrapped functions. But this seems like a more minimal change. --- pandas/core/apply.py | 5 +++-- pandas/tests/groupby/test_any_all.py | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/pandas/core/apply.py b/pandas/core/apply.py index 6ac8857582153..51407752b733f 100644 --- a/pandas/core/apply.py +++ b/pandas/core/apply.py @@ -552,10 +552,11 @@ def apply_str(self) -> DataFrame | Series: if callable(func): sig = inspect.getfullargspec(func) if self.axis != 0 and ( - "axis" not in sig.args or f in ("corrwith", "mad", "skew") + ("axis" not in sig.args and "axis" not in sig.kwonlyargs) + or f in ("corrwith", "mad", "skew") ): raise ValueError(f"Operation {f} does not support axis=1") - elif "axis" in sig.args: + elif "axis" in sig.args or "axis" in sig.kwonlyargs: self.kwargs["axis"] = self.axis return self._try_aggregate_string_function(obj, f, *self.args, **self.kwargs) diff --git a/pandas/tests/groupby/test_any_all.py b/pandas/tests/groupby/test_any_all.py index 784ff1069e7ff..faa425d932f1b 100644 --- a/pandas/tests/groupby/test_any_all.py +++ b/pandas/tests/groupby/test_any_all.py @@ -83,6 +83,23 @@ def test_any_non_keyword_deprecation(): tm.assert_equal(result, expected) +def test_any_apply_keyword_non_zero_axis_regression(): + # https://github.com/pandas-dev/pandas/issues/48656 + df = DataFrame({"A": [1, 2], "B": [0, 2], "C": [0, 0]}) + expected = df.any(axis=1) + result = df.apply('any', axis=1) + tm.assert_series_equal(result, expected) + + msg = ( + "In a future version of pandas all arguments of " + "DataFrame.any and Series.any will be keyword-only." + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + expected = df.any(1) + result = df.apply('any', 1) + tm.assert_series_equal(result, expected) + + @pytest.mark.parametrize("bool_agg_func", ["any", "all"]) def test_bool_aggs_dup_column_labels(bool_agg_func): # 21668 From 682d7f92865b082d1cec4a8cb69de02f43795620 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Mon, 26 Sep 2022 16:25:45 -0700 Subject: [PATCH 2/6] black --- pandas/tests/groupby/test_any_all.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/groupby/test_any_all.py b/pandas/tests/groupby/test_any_all.py index faa425d932f1b..3d69cdd47a380 100644 --- a/pandas/tests/groupby/test_any_all.py +++ b/pandas/tests/groupby/test_any_all.py @@ -87,7 +87,7 @@ def test_any_apply_keyword_non_zero_axis_regression(): # https://github.com/pandas-dev/pandas/issues/48656 df = DataFrame({"A": [1, 2], "B": [0, 2], "C": [0, 0]}) expected = df.any(axis=1) - result = df.apply('any', axis=1) + result = df.apply("any", axis=1) tm.assert_series_equal(result, expected) msg = ( @@ -96,7 +96,7 @@ def test_any_apply_keyword_non_zero_axis_regression(): ) with tm.assert_produces_warning(FutureWarning, match=msg): expected = df.any(1) - result = df.apply('any', 1) + result = df.apply("any", 1) tm.assert_series_equal(result, expected) From e6a120d22c5a6e879810fe63a9b7f0ed414433c8 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Tue, 27 Sep 2022 14:05:44 -0700 Subject: [PATCH 3/6] whats new --- doc/source/whatsnew/v1.5.1.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.5.1.rst b/doc/source/whatsnew/v1.5.1.rst index 8eb77f890245a..a0044004a35d0 100644 --- a/doc/source/whatsnew/v1.5.1.rst +++ b/doc/source/whatsnew/v1.5.1.rst @@ -76,6 +76,7 @@ Fixed regressions - Fixed regression in :meth:`DataFrame.plot` ignoring invalid ``colormap`` for ``kind="scatter"`` (:issue:`48726`) - Fixed performance regression in :func:`factorize` when ``na_sentinel`` is not ``None`` and ``sort=False`` (:issue:`48620`) - Fixed regression causing an ``AttributeError`` during warning emitted if the provided table name in :meth:`DataFrame.to_sql` and the table name actually used in the database do not match (:issue:`48733`) +- Fixed regression in :meth:`DataFrame.apply` when passing non-zero ``axis`` via keyword argument (:issue:`48656`) .. --------------------------------------------------------------------------- From f004e81e2276555a089decfa3da0d571e8b9dd39 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Wed, 28 Sep 2022 15:43:02 -0700 Subject: [PATCH 4/6] code review --- pandas/core/apply.py | 6 +++--- pandas/tests/groupby/test_any_all.py | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/pandas/core/apply.py b/pandas/core/apply.py index 51407752b733f..91826f38e20e7 100644 --- a/pandas/core/apply.py +++ b/pandas/core/apply.py @@ -551,12 +551,12 @@ def apply_str(self) -> DataFrame | Series: func = getattr(obj, f, None) if callable(func): sig = inspect.getfullargspec(func) + arg_names = (*sig.args, *sig.kwonlyargs) if self.axis != 0 and ( - ("axis" not in sig.args and "axis" not in sig.kwonlyargs) - or f in ("corrwith", "mad", "skew") + "axis" not in arg_names or f in ("corrwith", "mad", "skew") ): raise ValueError(f"Operation {f} does not support axis=1") - elif "axis" in sig.args or "axis" in sig.kwonlyargs: + elif "axis" in arg_names: self.kwargs["axis"] = self.axis return self._try_aggregate_string_function(obj, f, *self.args, **self.kwargs) diff --git a/pandas/tests/groupby/test_any_all.py b/pandas/tests/groupby/test_any_all.py index 3d69cdd47a380..7644936c953f4 100644 --- a/pandas/tests/groupby/test_any_all.py +++ b/pandas/tests/groupby/test_any_all.py @@ -85,8 +85,10 @@ def test_any_non_keyword_deprecation(): def test_any_apply_keyword_non_zero_axis_regression(): # https://github.com/pandas-dev/pandas/issues/48656 - df = DataFrame({"A": [1, 2], "B": [0, 2], "C": [0, 0]}) - expected = df.any(axis=1) + df = DataFrame({"A": [1, 2, 0], "B": [0, 2, 0], "C": [0, 0, 0]}) + expected = Series([True, True, False]) + tm.assert_series_equal(df.any(axis=1), expected) + result = df.apply("any", axis=1) tm.assert_series_equal(result, expected) From 5b7b7dfb6480adf22c60bfc5c1983feda3c385aa Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Thu, 29 Sep 2022 19:46:43 -0700 Subject: [PATCH 5/6] simplify test --- pandas/tests/groupby/test_any_all.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pandas/tests/groupby/test_any_all.py b/pandas/tests/groupby/test_any_all.py index 7644936c953f4..96d5ecd399049 100644 --- a/pandas/tests/groupby/test_any_all.py +++ b/pandas/tests/groupby/test_any_all.py @@ -92,12 +92,6 @@ def test_any_apply_keyword_non_zero_axis_regression(): result = df.apply("any", axis=1) tm.assert_series_equal(result, expected) - msg = ( - "In a future version of pandas all arguments of " - "DataFrame.any and Series.any will be keyword-only." - ) - with tm.assert_produces_warning(FutureWarning, match=msg): - expected = df.any(1) result = df.apply("any", 1) tm.assert_series_equal(result, expected) From 7590d904742fde1a04749ae6636009aa6514c206 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Thu, 29 Sep 2022 19:47:15 -0700 Subject: [PATCH 6/6] move tests --- pandas/tests/apply/test_frame_apply.py | 35 ++++++++++++++++++++++++++ pandas/tests/groupby/test_any_all.py | 35 -------------------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/pandas/tests/apply/test_frame_apply.py b/pandas/tests/apply/test_frame_apply.py index d2882f46d25bf..3bcb7d964fad1 100644 --- a/pandas/tests/apply/test_frame_apply.py +++ b/pandas/tests/apply/test_frame_apply.py @@ -1604,3 +1604,38 @@ def test_unique_agg_type_is_series(test, constant): result = df1.agg(aggregation) tm.assert_series_equal(result, expected) + + +def test_any_non_keyword_deprecation(): + df = DataFrame({"A": [1, 2], "B": [0, 2], "C": [0, 0]}) + msg = ( + "In a future version of pandas all arguments of " + "DataFrame.any and Series.any will be keyword-only." + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + result = df.any("index", None) + expected = Series({"A": True, "B": True, "C": False}) + tm.assert_series_equal(result, expected) + + s = Series([False, False, False]) + msg = ( + "In a future version of pandas all arguments of " + "DataFrame.any and Series.any will be keyword-only." + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + result = s.any("index") + expected = False + tm.assert_equal(result, expected) + + +def test_any_apply_keyword_non_zero_axis_regression(): + # https://github.com/pandas-dev/pandas/issues/48656 + df = DataFrame({"A": [1, 2, 0], "B": [0, 2, 0], "C": [0, 0, 0]}) + expected = Series([True, True, False]) + tm.assert_series_equal(df.any(axis=1), expected) + + result = df.apply("any", axis=1) + tm.assert_series_equal(result, expected) + + result = df.apply("any", 1) + tm.assert_series_equal(result, expected) diff --git a/pandas/tests/groupby/test_any_all.py b/pandas/tests/groupby/test_any_all.py index 96d5ecd399049..3f61a4ece66c0 100644 --- a/pandas/tests/groupby/test_any_all.py +++ b/pandas/tests/groupby/test_any_all.py @@ -61,41 +61,6 @@ def test_any(): tm.assert_frame_equal(result, expected) -def test_any_non_keyword_deprecation(): - df = DataFrame({"A": [1, 2], "B": [0, 2], "C": [0, 0]}) - msg = ( - "In a future version of pandas all arguments of " - "DataFrame.any and Series.any will be keyword-only." - ) - with tm.assert_produces_warning(FutureWarning, match=msg): - result = df.any("index", None) - expected = Series({"A": True, "B": True, "C": False}) - tm.assert_series_equal(result, expected) - - s = Series([False, False, False]) - msg = ( - "In a future version of pandas all arguments of " - "DataFrame.any and Series.any will be keyword-only." - ) - with tm.assert_produces_warning(FutureWarning, match=msg): - result = s.any("index") - expected = False - tm.assert_equal(result, expected) - - -def test_any_apply_keyword_non_zero_axis_regression(): - # https://github.com/pandas-dev/pandas/issues/48656 - df = DataFrame({"A": [1, 2, 0], "B": [0, 2, 0], "C": [0, 0, 0]}) - expected = Series([True, True, False]) - tm.assert_series_equal(df.any(axis=1), expected) - - result = df.apply("any", axis=1) - tm.assert_series_equal(result, expected) - - result = df.apply("any", 1) - tm.assert_series_equal(result, expected) - - @pytest.mark.parametrize("bool_agg_func", ["any", "all"]) def test_bool_aggs_dup_column_labels(bool_agg_func): # 21668