From 14f610c31a48f5caec9465207cb1906ffd19373c Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sun, 30 Nov 2025 14:08:09 +0100 Subject: [PATCH 1/4] Fix `Series.map` default for `na_action` --- pandas-stubs/core/series.pyi | 4 ++-- tests/series/test_series.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 9b5fc9619..449e6afd5 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -1107,7 +1107,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): def map( self, arg: Callable[[S1], S2 | NAType] | Mapping[S1, S2] | Series[S2], - na_action: Literal["ignore"] = ..., + na_action: Literal["ignore"], ) -> Series[S2]: ... @overload def map( @@ -1119,7 +1119,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): def map( self, arg: Callable[[Any], Any] | Mapping[Any, Any] | Series, - na_action: Literal["ignore"] | None = ..., + na_action: Literal["ignore"] | None = None, ) -> Series: ... @overload def aggregate( diff --git a/tests/series/test_series.py b/tests/series/test_series.py index dc2417a8d..1da3f3335 100644 --- a/tests/series/test_series.py +++ b/tests/series/test_series.py @@ -3620,6 +3620,8 @@ def callable(x: int | NAType) -> str | NAType: check( assert_type(s.map(callable, na_action=None), "pd.Series[str]"), pd.Series, str ) + # na_action defaults to None + check(assert_type(s.map(callable), "pd.Series[str]"), pd.Series, str) series = pd.Series(["a", "b", "c"]) check(assert_type(s.map(series, na_action=None), "pd.Series[str]"), pd.Series, str) From 00baef9b0a2b93708aecdcdf84ff9760491b7dbe Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sun, 30 Nov 2025 21:36:54 +0100 Subject: [PATCH 2/4] Simplify and add more tests --- pandas-stubs/core/series.pyi | 21 ++++++--------------- tests/series/test_series.py | 26 +++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 449e6afd5..6ff0b2f12 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -1103,24 +1103,15 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): fill_value: int | _str | dict | None = None, sort: _bool = True, ) -> DataFrame: ... - @overload - def map( - self, - arg: Callable[[S1], S2 | NAType] | Mapping[S1, S2] | Series[S2], - na_action: Literal["ignore"], - ) -> Series[S2]: ... - @overload - def map( - self, - arg: Callable[[S1 | NAType], S2 | NAType] | Mapping[S1, S2] | Series[S2], - na_action: None = None, - ) -> Series[S2]: ... - @overload def map( self, - arg: Callable[[Any], Any] | Mapping[Any, Any] | Series, + arg: ( + Callable[[S1], S2 | None | NAType] + | Mapping[S1, S2 | None | NAType] + | Series[S2] + ), na_action: Literal["ignore"] | None = None, - ) -> Series: ... + ) -> Series[S2]: ... @overload def aggregate( self: Series[int], diff --git a/tests/series/test_series.py b/tests/series/test_series.py index 1da3f3335..24513a1c8 100644 --- a/tests/series/test_series.py +++ b/tests/series/test_series.py @@ -3584,6 +3584,7 @@ def test_map() -> None: pd.Series, str, ) + check(assert_type(s.map(mapping), "pd.Series[str]"), pd.Series, str) def callable(x: int) -> str: return str(x) @@ -3593,16 +3594,29 @@ def callable(x: int) -> str: pd.Series, str, ) + check(assert_type(s.map(callable), "pd.Series[str]"), pd.Series, str) series = pd.Series(["a", "b", "c"]) check( assert_type(s.map(series, na_action="ignore"), "pd.Series[str]"), pd.Series, str ) + check(assert_type(s.map(series), "pd.Series[str]"), pd.Series, str) unknown_series = pd.Series([1, 0, None]) check( - assert_type(unknown_series.map({1: True, 0: False, None: None}), pd.Series), + assert_type( + unknown_series.map({1: True, 0: False, None: None}), "pd.Series[bool]" + ), + pd.Series, + bool, + ) + check( + assert_type( + unknown_series.map({1: True, 0: False, None: None}, na_action="ignore"), + "pd.Series[bool]", + ), pd.Series, + bool, ) @@ -3626,6 +3640,16 @@ def callable(x: int | NAType) -> str | NAType: series = pd.Series(["a", "b", "c"]) check(assert_type(s.map(series, na_action=None), "pd.Series[str]"), pd.Series, str) + def callable2(x: int | NAType | None) -> str | None: + if isinstance(x, int): + return str(x) + return None + + check( + assert_type(s.map(callable2, na_action=None), "pd.Series[str]"), pd.Series, str + ) + check(assert_type(s.map(callable2), "pd.Series[str]"), pd.Series, str) + def test_case_when() -> None: c = pd.Series([6, 7, 8, 9], name="c") From 654d505c9d9d727f885ae7de3644c7b49ee9074e Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sun, 7 Dec 2025 14:07:54 +0100 Subject: [PATCH 3/4] Add test --- tests/series/test_series.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/series/test_series.py b/tests/series/test_series.py index 24513a1c8..d1f82383c 100644 --- a/tests/series/test_series.py +++ b/tests/series/test_series.py @@ -3618,6 +3618,12 @@ def callable(x: int) -> str: pd.Series, bool, ) + s_mixed = pd.Series([1, "a"]) + check( + assert_type(s_mixed.map({1: 1.0, "a": 2.0}), "pd.Series[float]"), + pd.Series, + float, + ) def test_map_na() -> None: From b672627ea92c1b46cf262a2ebeda32821d6bdec1 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sun, 7 Dec 2025 14:15:40 +0100 Subject: [PATCH 4/4] Add overload for mixed mappings --- pandas-stubs/core/series.pyi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 6ff0b2f12..ec95f36a4 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -1103,6 +1103,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): fill_value: int | _str | dict | None = None, sort: _bool = True, ) -> DataFrame: ... + @overload def map( self, arg: ( @@ -1113,6 +1114,12 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): na_action: Literal["ignore"] | None = None, ) -> Series[S2]: ... @overload + def map( + self, + arg: Callable[[Any], object] | Mapping[Any, object] | Series[Any], + na_action: Literal["ignore"] | None = None, + ) -> Series: ... + @overload def aggregate( self: Series[int], func: Literal["mean"],