From 950dc347ef8f0123d0d5fad1a8f433cda827a09c Mon Sep 17 00:00:00 2001 From: stanleycai95 <46463107+stanleycai95@users.noreply.github.com> Date: Sun, 24 Apr 2022 12:47:54 -0400 Subject: [PATCH 01/14] _map_values for Series, na_action must be None or "ignore" --- pandas/core/base.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pandas/core/base.py b/pandas/core/base.py index e03b05f539e8f..8c17ea58f3e7f 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -842,6 +842,13 @@ def _map_values(self, mapper, na_action=None): ) if isinstance(mapper, ABCSeries): + # na_action must be None or "ignore" + if na_action not in [None, "ignore"]: + msg = ( + "na_action must either be 'ignore' or None, " + f"{na_action} was passed" + ) + raise ValueError(msg) # Since values were input this means we came from either # a dict or a series and mapper should be an index if is_categorical_dtype(self.dtype): From e3cc14e73764f3b1d3a7c59e958a85074158fad5 Mon Sep 17 00:00:00 2001 From: stanleycai95 <46463107+stanleycai95@users.noreply.github.com> Date: Sun, 24 Apr 2022 12:59:23 -0400 Subject: [PATCH 02/14] Updating docstring for na_action in Series --- pandas/core/series.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index 1d3509cac0edd..68dfe3146683c 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -4264,8 +4264,7 @@ def map(self, arg, na_action=None) -> Series: arg : function, collections.abc.Mapping subclass or Series Mapping correspondence. na_action : {None, 'ignore'}, default None - If 'ignore', propagate NaN values, without passing them to the - mapping correspondence. + Not used. Returns ------- @@ -4316,13 +4315,12 @@ def map(self, arg, na_action=None) -> Series: 3 I am a rabbit dtype: object - To avoid applying the function to missing values (and keep them as - ``NaN``) ``na_action='ignore'`` can be used: + Setting ``na_action='ignore'`` does not change behavior: >>> s.map('I am a {}'.format, na_action='ignore') 0 I am a cat 1 I am a dog - 2 NaN + 2 I am a nan 3 I am a rabbit dtype: object """ From db5b2c49e4b7897ffb82d281d9b29e04e8745564 Mon Sep 17 00:00:00 2001 From: stanleycai95 <46463107+stanleycai95@users.noreply.github.com> Date: Sun, 24 Apr 2022 13:09:32 -0400 Subject: [PATCH 03/14] Revert to old docstring --- pandas/core/series.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index 68dfe3146683c..e5b1921eccb46 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -4264,7 +4264,8 @@ def map(self, arg, na_action=None) -> Series: arg : function, collections.abc.Mapping subclass or Series Mapping correspondence. na_action : {None, 'ignore'}, default None - Not used. + If 'ignore', propagate NA values, without passing them to the + mapping function Returns ------- @@ -4315,12 +4316,13 @@ def map(self, arg, na_action=None) -> Series: 3 I am a rabbit dtype: object - Setting ``na_action='ignore'`` does not change behavior: + To avoid applying the function to missing values (and keep them as + ``NaN``) ``na_action='ignore'`` can be used: >>> s.map('I am a {}'.format, na_action='ignore') 0 I am a cat 1 I am a dog - 2 I am a nan + 2 NaN 3 I am a rabbit dtype: object """ From 7d1d0367628aa4730eec411cd69fe4a8381abe06 Mon Sep 17 00:00:00 2001 From: stanleycai95 <46463107+stanleycai95@users.noreply.github.com> Date: Sun, 24 Apr 2022 13:12:48 -0400 Subject: [PATCH 04/14] Use tuple instead of list --- pandas/core/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/base.py b/pandas/core/base.py index 8c17ea58f3e7f..01ed55868fa54 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -843,7 +843,7 @@ def _map_values(self, mapper, na_action=None): if isinstance(mapper, ABCSeries): # na_action must be None or "ignore" - if na_action not in [None, "ignore"]: + if na_action not in (None, "ignore"): msg = ( "na_action must either be 'ignore' or None, " f"{na_action} was passed" From d4db9a18aa8b78789104e4ec9b720a4c41740157 Mon Sep 17 00:00:00 2001 From: stanleycai95 <46463107+stanleycai95@users.noreply.github.com> Date: Sun, 24 Apr 2022 13:14:33 -0400 Subject: [PATCH 05/14] Revert to previous commit --- pandas/core/series.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index e5b1921eccb46..1d3509cac0edd 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -4264,8 +4264,8 @@ def map(self, arg, na_action=None) -> Series: arg : function, collections.abc.Mapping subclass or Series Mapping correspondence. na_action : {None, 'ignore'}, default None - If 'ignore', propagate NA values, without passing them to the - mapping function + If 'ignore', propagate NaN values, without passing them to the + mapping correspondence. Returns ------- From 283ddc158dce1b39592457f92375bfc3956f322d Mon Sep 17 00:00:00 2001 From: stanleycai95 <46463107+stanleycai95@users.noreply.github.com> Date: Sun, 24 Apr 2022 19:53:39 -0400 Subject: [PATCH 06/14] Add test for map with invalid na_action argument --- pandas/tests/apply/test_invalid_arg.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pandas/tests/apply/test_invalid_arg.py b/pandas/tests/apply/test_invalid_arg.py index 410a8f6bf3965..07ad9861032ee 100644 --- a/pandas/tests/apply/test_invalid_arg.py +++ b/pandas/tests/apply/test_invalid_arg.py @@ -64,6 +64,18 @@ def test_map_with_invalid_na_action_raises(): msg = "na_action must either be 'ignore' or None" with pytest.raises(ValueError, match=msg): s.map(lambda x: x, na_action="____") + + +def test_map_via_dict_with_invalid_na_action_raises(): + # https://github.com/pandas-dev/pandas/issues/46588 + s = Series([1, 2, 3]) + na_action = "____" + msg = ( + "na_action must either be 'ignore' or None, " + f"{na_action} was passed" + ) + with pytest.raises(ValueError, match=msg): + s.map({1: 2}, na_action="____") def test_map_categorical_na_action(): From aa01db56d9562e3700e3bc29d32fc88341eaf17b Mon Sep 17 00:00:00 2001 From: stanleycai95 <46463107+stanleycai95@users.noreply.github.com> Date: Sun, 24 Apr 2022 19:59:19 -0400 Subject: [PATCH 07/14] Conforming to pep style --- pandas/tests/apply/test_invalid_arg.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pandas/tests/apply/test_invalid_arg.py b/pandas/tests/apply/test_invalid_arg.py index 07ad9861032ee..926ee02ac1d95 100644 --- a/pandas/tests/apply/test_invalid_arg.py +++ b/pandas/tests/apply/test_invalid_arg.py @@ -64,16 +64,16 @@ def test_map_with_invalid_na_action_raises(): msg = "na_action must either be 'ignore' or None" with pytest.raises(ValueError, match=msg): s.map(lambda x: x, na_action="____") - -def test_map_via_dict_with_invalid_na_action_raises(): + +def test_map_arg_is_dict_with_invalid_na_action_raises(): # https://github.com/pandas-dev/pandas/issues/46588 s = Series([1, 2, 3]) na_action = "____" msg = ( - "na_action must either be 'ignore' or None, " - f"{na_action} was passed" - ) + "na_action must either be 'ignore' or None, " + f"{na_action} was passed" + ) with pytest.raises(ValueError, match=msg): s.map({1: 2}, na_action="____") From 8c8527e50717db7eb4739a5f38421fdd26b50856 Mon Sep 17 00:00:00 2001 From: stanleycai95 <46463107+stanleycai95@users.noreply.github.com> Date: Sun, 24 Apr 2022 20:08:17 -0400 Subject: [PATCH 08/14] Series.map raises if arg is dict but na_action not None or ignore --- doc/source/whatsnew/v1.5.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.5.0.rst b/doc/source/whatsnew/v1.5.0.rst index e4879a6c41515..0919a55a35541 100644 --- a/doc/source/whatsnew/v1.5.0.rst +++ b/doc/source/whatsnew/v1.5.0.rst @@ -79,6 +79,7 @@ as seen in the following example. Other enhancements ^^^^^^^^^^^^^^^^^^ +- :meth:`Series.map` now raises when ``arg`` is dict but ``na_action`` is not either None or 'ignore' (:issue:`46588`) - :meth:`MultiIndex.to_frame` now supports the argument ``allow_duplicates`` and raises on duplicate labels if it is missing or False (:issue:`45245`) - :class:`StringArray` now accepts array-likes containing nan-likes (``None``, ``np.nan``) for the ``values`` parameter in its constructor in addition to strings and :attr:`pandas.NA`. (:issue:`40839`) - Improved the rendering of ``categories`` in :class:`CategoricalIndex` (:issue:`45218`) From 8f99a1f773f18a76cd1a348954a05234faaf40e2 Mon Sep 17 00:00:00 2001 From: stanleycai95 <46463107+stanleycai95@users.noreply.github.com> Date: Sun, 24 Apr 2022 20:19:40 -0400 Subject: [PATCH 09/14] Update msg --- pandas/tests/apply/test_invalid_arg.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pandas/tests/apply/test_invalid_arg.py b/pandas/tests/apply/test_invalid_arg.py index 926ee02ac1d95..144835bde1d26 100644 --- a/pandas/tests/apply/test_invalid_arg.py +++ b/pandas/tests/apply/test_invalid_arg.py @@ -70,10 +70,7 @@ def test_map_arg_is_dict_with_invalid_na_action_raises(): # https://github.com/pandas-dev/pandas/issues/46588 s = Series([1, 2, 3]) na_action = "____" - msg = ( - "na_action must either be 'ignore' or None, " - f"{na_action} was passed" - ) + msg = "na_action must either be 'ignore' or None, " f"{na_action} was passed" with pytest.raises(ValueError, match=msg): s.map({1: 2}, na_action="____") From 6cb08b3d8e8d2cb69e5b5b901855751ae8bb738e Mon Sep 17 00:00:00 2001 From: stanleycai95 <46463107+stanleycai95@users.noreply.github.com> Date: Sun, 24 Apr 2022 20:26:58 -0400 Subject: [PATCH 10/14] Update f-string --- pandas/tests/apply/test_invalid_arg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/apply/test_invalid_arg.py b/pandas/tests/apply/test_invalid_arg.py index 144835bde1d26..c18a02fb3b8ea 100644 --- a/pandas/tests/apply/test_invalid_arg.py +++ b/pandas/tests/apply/test_invalid_arg.py @@ -70,7 +70,7 @@ def test_map_arg_is_dict_with_invalid_na_action_raises(): # https://github.com/pandas-dev/pandas/issues/46588 s = Series([1, 2, 3]) na_action = "____" - msg = "na_action must either be 'ignore' or None, " f"{na_action} was passed" + msg = f"na_action must either be 'ignore' or None, {na_action} was passed" with pytest.raises(ValueError, match=msg): s.map({1: 2}, na_action="____") From 151b608914fbedae8b825289e66bf1e3bf617f3a Mon Sep 17 00:00:00 2001 From: stanleycai95 <46463107+stanleycai95@users.noreply.github.com> Date: Mon, 25 Apr 2022 07:39:41 -0400 Subject: [PATCH 11/14] Use pytest.mark.parametrize --- pandas/tests/apply/test_invalid_arg.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/tests/apply/test_invalid_arg.py b/pandas/tests/apply/test_invalid_arg.py index c18a02fb3b8ea..37f5175d58b88 100644 --- a/pandas/tests/apply/test_invalid_arg.py +++ b/pandas/tests/apply/test_invalid_arg.py @@ -66,13 +66,13 @@ def test_map_with_invalid_na_action_raises(): s.map(lambda x: x, na_action="____") -def test_map_arg_is_dict_with_invalid_na_action_raises(): +@pytest.mark.parametrize("na_action", ["____", True]) +def test_map_arg_is_dict_with_invalid_na_action_raises(na_action): # https://github.com/pandas-dev/pandas/issues/46588 s = Series([1, 2, 3]) - na_action = "____" msg = f"na_action must either be 'ignore' or None, {na_action} was passed" with pytest.raises(ValueError, match=msg): - s.map({1: 2}, na_action="____") + s.map({1: 2}, na_action=na_action) def test_map_categorical_na_action(): From b905214e082435ccbf9798d599a036f1a40986d3 Mon Sep 17 00:00:00 2001 From: stanleycai95 <46463107+stanleycai95@users.noreply.github.com> Date: Mon, 25 Apr 2022 10:11:04 -0400 Subject: [PATCH 12/14] Update variable names --- pandas/tests/apply/test_invalid_arg.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/tests/apply/test_invalid_arg.py b/pandas/tests/apply/test_invalid_arg.py index 37f5175d58b88..6ad46ed209cf7 100644 --- a/pandas/tests/apply/test_invalid_arg.py +++ b/pandas/tests/apply/test_invalid_arg.py @@ -66,13 +66,13 @@ def test_map_with_invalid_na_action_raises(): s.map(lambda x: x, na_action="____") -@pytest.mark.parametrize("na_action", ["____", True]) -def test_map_arg_is_dict_with_invalid_na_action_raises(na_action): +@pytest.mark.parametrize("input_na_action", ["____", True]) +def test_map_arg_is_dict_with_invalid_na_action_raises(input_na_action): # https://github.com/pandas-dev/pandas/issues/46588 s = Series([1, 2, 3]) - msg = f"na_action must either be 'ignore' or None, {na_action} was passed" + msg = f"na_action must either be 'ignore' or None, {input_na_action} was passed" with pytest.raises(ValueError, match=msg): - s.map({1: 2}, na_action=na_action) + s.map({1: 2}, na_action=input_na_action) def test_map_categorical_na_action(): From 85b6ebd2bc30cd78347106d898637bc2392730f9 Mon Sep 17 00:00:00 2001 From: stanleycai95 <46463107+stanleycai95@users.noreply.github.com> Date: Mon, 25 Apr 2022 21:46:13 -0400 Subject: [PATCH 13/14] Adding backticks --- doc/source/whatsnew/v1.5.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.5.0.rst b/doc/source/whatsnew/v1.5.0.rst index 0919a55a35541..90586920120e0 100644 --- a/doc/source/whatsnew/v1.5.0.rst +++ b/doc/source/whatsnew/v1.5.0.rst @@ -79,7 +79,7 @@ as seen in the following example. Other enhancements ^^^^^^^^^^^^^^^^^^ -- :meth:`Series.map` now raises when ``arg`` is dict but ``na_action`` is not either None or 'ignore' (:issue:`46588`) +- :meth:`Series.map` now raises when ``arg`` is dict but ``na_action`` is not either ``None`` or ``'ignore'`` (:issue:`46588`) - :meth:`MultiIndex.to_frame` now supports the argument ``allow_duplicates`` and raises on duplicate labels if it is missing or False (:issue:`45245`) - :class:`StringArray` now accepts array-likes containing nan-likes (``None``, ``np.nan``) for the ``values`` parameter in its constructor in addition to strings and :attr:`pandas.NA`. (:issue:`40839`) - Improved the rendering of ``categories`` in :class:`CategoricalIndex` (:issue:`45218`) From 83a835a6d965c56b59467687f9563127be1245fe Mon Sep 17 00:00:00 2001 From: stanleycai95 <46463107+stanleycai95@users.noreply.github.com> Date: Mon, 25 Apr 2022 21:47:56 -0400 Subject: [PATCH 14/14] Removing extraneous comment --- pandas/core/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/core/base.py b/pandas/core/base.py index 01ed55868fa54..ce11f31281f5d 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -842,7 +842,6 @@ def _map_values(self, mapper, na_action=None): ) if isinstance(mapper, ABCSeries): - # na_action must be None or "ignore" if na_action not in (None, "ignore"): msg = ( "na_action must either be 'ignore' or None, "