From 4b1d5b5bdf41c710981a3cd1227f2b58f55c0052 Mon Sep 17 00:00:00 2001 From: Yury Bayda Date: Wed, 15 Aug 2018 17:21:38 -0700 Subject: [PATCH 1/3] BUG: Fix DataFrame.apply for string arg with additional args (#22376) --- doc/source/whatsnew/v0.24.0.txt | 1 + pandas/core/apply.py | 3 ++- pandas/tests/frame/test_apply.py | 11 ++++------- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index cf12759c051fc..4265d481ddb69 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -625,6 +625,7 @@ Numeric a ``TypeError`` was wrongly raised. For all three methods such calculation are now done correctly. (:issue:`16679`). - Bug in :class:`Series` comparison against datetime-like scalars and arrays (:issue:`22074`) - Bug in :class:`DataFrame` multiplication between boolean dtype and integer returning ``object`` dtype instead of integer dtype (:issue:`22047`,:issue:`22163`) +- Bug in :meth:`DataFrame.apply` where, when supplied with a string argument and additional positional or keyword arguments (e.g. ``df.apply('sum', min_count=1)``), a ``TypeError`` was wrongly raised (:issue:`22376`) - Strings diff --git a/pandas/core/apply.py b/pandas/core/apply.py index 989becbf133ca..6b92cb9ebf2f8 100644 --- a/pandas/core/apply.py +++ b/pandas/core/apply.py @@ -71,7 +71,8 @@ def __init__(self, obj, func, broadcast, raw, reduce, result_type, self.result_type = result_type # curry if needed - if kwds or args and not isinstance(func, np.ufunc): + if (kwds or args) and not isinstance(func, (np.ufunc, + compat.string_types)): def f(x): return func(x, *args, **kwds) else: diff --git a/pandas/tests/frame/test_apply.py b/pandas/tests/frame/test_apply.py index f18163d51c721..99888db4de110 100644 --- a/pandas/tests/frame/test_apply.py +++ b/pandas/tests/frame/test_apply.py @@ -121,13 +121,10 @@ def test_apply_standard_nonunique(self): assert_series_equal(rs, xp) @pytest.mark.parametrize('arg', ['sum', 'mean', 'min', 'max', 'std']) - def test_with_string_args(self, arg): - result = self.frame.apply(arg) - expected = getattr(self.frame, arg)() - tm.assert_series_equal(result, expected) - - result = self.frame.apply(arg, axis=1) - expected = getattr(self.frame, arg)(axis=1) + @pytest.mark.parametrize('kwds', [{}, {'axis': 1}, {'numeric_only': True}]) + def test_with_string_args(self, arg, kwds): + result = self.frame.apply(arg, **kwds) + expected = getattr(self.frame, arg)(**kwds) tm.assert_series_equal(result, expected) def test_apply_broadcast_deprecated(self): From a0515925a3e5d6ef405a37738be44304c3abfce5 Mon Sep 17 00:00:00 2001 From: Yury Bayda Date: Thu, 16 Aug 2018 12:34:18 -0700 Subject: [PATCH 2/3] Add tests for args and kwargs combinations --- pandas/tests/frame/test_apply.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/pandas/tests/frame/test_apply.py b/pandas/tests/frame/test_apply.py index 99888db4de110..8beab3fb816df 100644 --- a/pandas/tests/frame/test_apply.py +++ b/pandas/tests/frame/test_apply.py @@ -120,11 +120,17 @@ def test_apply_standard_nonunique(self): rs = df.T.apply(lambda s: s[0], axis=0) assert_series_equal(rs, xp) - @pytest.mark.parametrize('arg', ['sum', 'mean', 'min', 'max', 'std']) - @pytest.mark.parametrize('kwds', [{}, {'axis': 1}, {'numeric_only': True}]) - def test_with_string_args(self, arg, kwds): - result = self.frame.apply(arg, **kwds) - expected = getattr(self.frame, arg)(**kwds) + @pytest.mark.parametrize('func', ['sum', 'mean', 'min', 'max', 'std']) + @pytest.mark.parametrize('args,kwds', [ + pytest.param([], {}, id='no_args_or_kwds'), + pytest.param([1], {}, id='axis_from_args'), + pytest.param([], {'axis': 1}, id='axis_from_kwds'), + pytest.param([], {'numeric_only': True}, id='optional_kwds'), + pytest.param([1, None], {'numeric_only': True}, id='args_and_kwds') + ]) + def test_apply_with_string_funcs(self, func, args, kwds): + result = self.frame.apply(func, *args, **kwds) + expected = getattr(self.frame, func)(*args, **kwds) tm.assert_series_equal(result, expected) def test_apply_broadcast_deprecated(self): From 48d283ab359efe8f7ab468eee16d0446b2b87589 Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Thu, 23 Aug 2018 06:42:00 -0400 Subject: [PATCH 3/3] lint --- pandas/core/apply.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pandas/core/apply.py b/pandas/core/apply.py index 6b92cb9ebf2f8..40cd952a62138 100644 --- a/pandas/core/apply.py +++ b/pandas/core/apply.py @@ -71,8 +71,9 @@ def __init__(self, obj, func, broadcast, raw, reduce, result_type, self.result_type = result_type # curry if needed - if (kwds or args) and not isinstance(func, (np.ufunc, - compat.string_types)): + if ((kwds or args) and + not isinstance(func, (np.ufunc, compat.string_types))): + def f(x): return func(x, *args, **kwds) else: