From b3fda18520dd28c75fcaa09aa2af5d6af9ac0086 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Sun, 13 Jul 2025 18:17:11 +0200 Subject: [PATCH 1/8] refactor: minimal systematic implementation --- pandas-stubs/core/series.pyi | 24 +++++- pyproject.toml | 2 +- tests/series/__init__.py | 0 tests/series/arithmetic/__init__.py | 0 tests/series/arithmetic/int/__init__.py | 0 tests/series/arithmetic/int/test_add.py | 104 +++++++++++++++++++++++ tests/series/arithmetic/test_add.py | 105 ++++++++++++++++++++++++ tests/{ => series}/test_series.py | 7 +- tests/test_frame.py | 22 ++++- 9 files changed, 256 insertions(+), 8 deletions(-) create mode 100644 tests/series/__init__.py create mode 100644 tests/series/arithmetic/__init__.py create mode 100644 tests/series/arithmetic/int/__init__.py create mode 100644 tests/series/arithmetic/int/test_add.py create mode 100644 tests/series/arithmetic/test_add.py rename tests/{ => series}/test_series.py (99%) diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 0fac9a3de..17d2cc1fc 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -175,6 +175,8 @@ from pandas._typing import ( VoidDtypeArg, WriteBuffer, np_ndarray_anyint, + np_ndarray_complex, + np_ndarray_float, npt, num, ) @@ -1613,6 +1615,10 @@ class Series(IndexOpsMixin[S1], NDFrame): # just failed to generate these so I couldn't match # them up. @overload + def __add__( + self: Series[int], other: int | Sequence[int] | Series[int] + ) -> Series[int]: ... + @overload def __add__(self, other: S1 | Self) -> Self: ... @overload def __add__( @@ -1739,7 +1745,14 @@ class Series(IndexOpsMixin[S1], NDFrame): # Methods def add( self, - other: Series[S1] | Scalar, + other: ( + Sequence[S1] + | np_ndarray_anyint + | np_ndarray_float + | np_ndarray_complex + | Series[S1] + | Scalar + ), level: Level | None = ..., fill_value: float | None = ..., axis: int = ..., @@ -1985,7 +1998,14 @@ class Series(IndexOpsMixin[S1], NDFrame): ) -> Scalar: ... def radd( self, - other: Series[S1] | Scalar, + other: ( + Sequence[S1] + | np_ndarray_anyint + | np_ndarray_float + | np_ndarray_complex + | Series[S1] + | Scalar + ), level: Level | None = ..., fill_value: float | None = ..., axis: AxisIndex = ..., diff --git a/pyproject.toml b/pyproject.toml index 71400163a..d916bfa93 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ mypy = "1.17.0" pandas = "2.3.0" pyarrow = ">=10.0.1" pytest = ">=7.1.2" -pyright = ">=1.1.400" +pyright = ">=1.1.403" ty = "^0.0.1a8" pyrefly = "^0.21.0" poethepoet = ">=0.16.5" diff --git a/tests/series/__init__.py b/tests/series/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/series/arithmetic/__init__.py b/tests/series/arithmetic/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/series/arithmetic/int/__init__.py b/tests/series/arithmetic/int/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/series/arithmetic/int/test_add.py b/tests/series/arithmetic/int/test_add.py new file mode 100644 index 000000000..1b6b75ced --- /dev/null +++ b/tests/series/arithmetic/int/test_add.py @@ -0,0 +1,104 @@ +from typing import assert_type + +import pandas as pd + +from tests import check + +left = pd.Series([1, 2, 3]) # left operand + + +def test_add_py_scalar() -> None: + """Test pd.Series[int] + Python native scalars""" + i, f, c = 1, 1.0, 1j + + check(assert_type(left + i, "pd.Series[int]"), pd.Series, int) + # check(assert_type(left + f, "pd.Series[float]"), pd.Series, float) + # check(assert_type(left + c, "pd.Series[complex]"), pd.Series, complex) + + check(assert_type(i + left, "pd.Series[int]"), pd.Series, int) + # check(assert_type(f + left, "pd.Series[float]"), pd.Series, float) + # check(assert_type(c + left, "pd.Series[complex]"), pd.Series, complex) + + check(assert_type(left.add(i), "pd.Series[int]"), pd.Series, int) + # check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, float) + # check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, complex) + + check(assert_type(left.radd(i), "pd.Series[int]"), pd.Series, int) + + +# check(assert_type(left.radd(f), "pd.Series[float]"), pd.Series, float) +# check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, complex) + + +def test_add_py_sequence() -> None: + """Test pd.Series[int] + Python native sequence""" + i, f, c = [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] + + check(assert_type(left + i, "pd.Series[int]"), pd.Series, int) + # check(assert_type(left + f, "pd.Series[float]"), pd.Series, float) + # check(assert_type(left + c, "pd.Series[complex]"), pd.Series, complex) + + # check(assert_type(i + left, "pd.Series[int]"), pd.Series, int) + # check(assert_type(f + left, "pd.Series[float]"), pd.Series, float) + # check(assert_type(c + left, "pd.Series[complex]"), pd.Series, complex) + + check(assert_type(left.add(i), "pd.Series[int]"), pd.Series, int) + + +# check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, float) +# check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, complex) + +# check(assert_type(left.radd(i), "pd.Series[int]"), pd.Series, int) +# check(assert_type(left.radd(f), "pd.Series[int]"), pd.Series, int) +# check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, complex) + + +# def test_add_numpy_array() -> None: +# """Test pd.Series[int] + numpy array""" +# i = np.array([2, 3, 5], np.int64) +# f = np.array([1.0, 2.0, 3.0], np.float64) +# c = np.array([1.1j, 2.2j, 4.1j], np.complex64) + +# check(assert_type(left + i, "pd.Series[int]"), pd.Series, int) +# check(assert_type(left + f, "pd.Series[float]"), pd.Series, float) +# check(assert_type(left + c, "pd.Series[complex]"), pd.Series, complex) + +# # check(assert_type(i + l, "pd.Series[int]"), pd.Series, int) +# # check(assert_type(f + l, "pd.Series[float]"), pd.Series, float) +# # check(assert_type(c + l, "pd.Series[complex]"), pd.Series, complex) + +# check(assert_type(left.add(i), "pd.Series[int]"), pd.Series, int) +# check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, float) +# check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, complex) + +# check(assert_type(left.radd(i), "pd.Series[int]"), pd.Series, int) +# check(assert_type(left.radd(f), "pd.Series[float]"), pd.Series, float) +# check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, complex) + + +def test_add_pd_series() -> None: + """Test pd.Series[int] + pandas series""" + i = pd.Series([2, 3, 5]) + # f = pd.Series([1.0, 2.0, 3.0]) + # c = pd.Series([1.1j, 2.2j, 4.1j]) + + check(assert_type(left + i, "pd.Series[int]"), pd.Series, int) + # check(assert_type(left + f, "pd.Series[float]"), pd.Series, float) + # check(assert_type(left + c, "pd.Series[complex]"), pd.Series, complex) + + # check( + # assert_type(i + left, pd.Series), "pd.Series[int]"), pd.Series, int) + # check( + # assert_type(f + left, "pd.Series[float]"), pd.Series, float) + # check( + # assert_type(c + left, pd.Series), "pd.Series[complex]"), pd.Series, complex) + + check(assert_type(left.add(i), "pd.Series[int]"), pd.Series, int) + # check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, float) + # check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, complex) + + check(assert_type(left.radd(i), "pd.Series[int]"), pd.Series, int) + + +# check(assert_type(left.radd(f), "pd.Series[float]"), pd.Series, float) +# check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, complex) diff --git a/tests/series/arithmetic/test_add.py b/tests/series/arithmetic/test_add.py new file mode 100644 index 000000000..2d2c5916a --- /dev/null +++ b/tests/series/arithmetic/test_add.py @@ -0,0 +1,105 @@ +from typing import assert_type + +import numpy as np +import pandas as pd + +from tests import check + +left = pd.DataFrame({"a": [1, 2, 3]})["a"] # left operand + + +def test_add_py_scalar() -> None: + """Test pd.Series[Any] + Python native scalars""" + i, f, c = 1, 1.0, 1j + + # check(assert_type(left + i, pd.Series), pd.Series) # why? + check(assert_type(left + f, pd.Series), pd.Series) + check(assert_type(left + c, pd.Series), pd.Series) + + check(assert_type(i + left, pd.Series), pd.Series) + check(assert_type(f + left, pd.Series), pd.Series) + check(assert_type(c + left, pd.Series), pd.Series) + + check(assert_type(left.add(i), pd.Series), pd.Series) + check(assert_type(left.add(f), pd.Series), pd.Series) + check(assert_type(left.add(c), pd.Series), pd.Series) + + check(assert_type(left.radd(i), pd.Series), pd.Series) + check(assert_type(left.radd(f), pd.Series), pd.Series) + check(assert_type(left.radd(c), pd.Series), pd.Series) + + +def test_add_py_sequence() -> None: + """Test pd.Series[Any] + Python native sequence""" + i, f, c = [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] + + # check(assert_type(left + i, pd.Series), pd.Series) # why? + check(assert_type(left + f, pd.Series), pd.Series) + check(assert_type(left + c, pd.Series), pd.Series) + + check(assert_type(i + left, pd.Series), pd.Series) + check(assert_type(f + left, pd.Series), pd.Series) + check(assert_type(c + left, pd.Series), pd.Series) + + check(assert_type(left.add(i), pd.Series), pd.Series) + check(assert_type(left.add(f), pd.Series), pd.Series) + check(assert_type(left.add(c), pd.Series), pd.Series) + + check(assert_type(left.radd(i), pd.Series), pd.Series) + check(assert_type(left.radd(f), pd.Series), pd.Series) + check(assert_type(left.radd(c), pd.Series), pd.Series) + + +def test_add_numpy_array() -> None: + """Test pd.Series[Any] + numpy array""" + i = np.array([2, 3, 5], np.int64) + f = np.array([1.0, 2.0, 3.0], np.float64) + c = np.array([1.1j, 2.2j, 4.1j], np.complex64) + + check(assert_type(left + i, pd.Series), pd.Series) + check(assert_type(left + f, pd.Series), pd.Series) + check(assert_type(left + c, pd.Series), pd.Series) + + # check(assert_type(i + l, pd.Series), pd.Series) + # check(assert_type(f + l, pd.Series), pd.Series) + # check(assert_type(c + l, pd.Series), pd.Series) + + check(assert_type(left.add(i), pd.Series), pd.Series) + check(assert_type(left.add(f), pd.Series), pd.Series) + check(assert_type(left.add(c), pd.Series), pd.Series) + + check(assert_type(left.radd(i), pd.Series), pd.Series) + check(assert_type(left.radd(f), pd.Series), pd.Series) + check(assert_type(left.radd(c), pd.Series), pd.Series) + + +def test_add_pd_series() -> None: + """Test pd.Series[Any] + pandas series""" + i = pd.Series([2, 3, 5]) + f = pd.Series([1.0, 2.0, 3.0]) + c = pd.Series([1.1j, 2.2j, 4.1j]) + + # check(assert_type(left + i, pd.Series), pd.Series) # why? + check(assert_type(left + f, pd.Series), pd.Series) + check(assert_type(left + c, pd.Series), pd.Series) + + check( + assert_type(i + left, pd.Series), # pyright: ignore[reportAssertTypeFailure] + pd.Series, + ) + check( + assert_type(f + left, pd.Series), # pyright: ignore[reportAssertTypeFailure] + pd.Series, + ) + check( + assert_type(c + left, pd.Series), # pyright: ignore[reportAssertTypeFailure] + pd.Series, + ) + + check(assert_type(left.add(i), pd.Series), pd.Series) + check(assert_type(left.add(f), pd.Series), pd.Series) + check(assert_type(left.add(c), pd.Series), pd.Series) + + check(assert_type(left.radd(i), pd.Series), pd.Series) + check(assert_type(left.radd(f), pd.Series), pd.Series) + check(assert_type(left.radd(c), pd.Series), pd.Series) diff --git a/tests/test_series.py b/tests/series/test_series.py similarity index 99% rename from tests/test_series.py rename to tests/series/test_series.py index 1e48aae75..fdfe7f09b 100644 --- a/tests/test_series.py +++ b/tests/series/test_series.py @@ -1599,7 +1599,10 @@ def test_series_min_max_sub_axis() -> None: ss = s1 - s2 sm = s1 * s2 sd = s1 / s2 - check(assert_type(sa, pd.Series), pd.Series) + check( + assert_type(sa, pd.Series), # pyright: ignore[reportAssertTypeFailure] # why? + pd.Series, + ) check(assert_type(ss, pd.Series), pd.Series) check(assert_type(sm, pd.Series), pd.Series) check(assert_type(sd, pd.Series), pd.Series) @@ -3892,7 +3895,7 @@ def foo(sf: pd.Series) -> None: pass foo(s) - check(assert_type(s + pd.Series([1]), pd.Series), pd.Series) + # check(assert_type(s + pd.Series([1]), pd.Series), pd.Series) # why? def test_series_items() -> None: diff --git a/tests/test_frame.py b/tests/test_frame.py index ffd85d609..b4d33fc1c 100644 --- a/tests/test_frame.py +++ b/tests/test_frame.py @@ -2819,9 +2819,25 @@ def test_sum_get_add() -> None: summer = df.sum(axis=1) check(assert_type(summer, pd.Series), pd.Series) - check(assert_type(s + summer, pd.Series), pd.Series) - check(assert_type(s + df["y"], pd.Series), pd.Series) - check(assert_type(summer + summer, pd.Series), pd.Series) + check( + assert_type( + s + summer, pd.Series # pyright: ignore[reportAssertTypeFailure] # why? + ), + pd.Series, + ) + check( + assert_type( + s + df["y"], pd.Series # pyright: ignore[reportAssertTypeFailure] # why? + ), + pd.Series, + ) + check( + assert_type( + summer + summer, # pyright: ignore[reportAssertTypeFailure] # why? + pd.Series, + ), + pd.Series, + ) def test_getset_untyped() -> None: From a63b9e445bc1155252a59558bc1063b262d7fbde Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 15 Jul 2025 16:26:54 +0200 Subject: [PATCH 2/8] feat: Series[int] + --- pandas-stubs/core/series.pyi | 135 ++++++++++++++++++++++-- tests/series/arithmetic/int/test_add.py | 120 ++++++++++----------- tests/series/arithmetic/test_add.py | 17 +-- tests/series/test_series.py | 5 +- tests/test_frame.py | 22 +--- 5 files changed, 191 insertions(+), 108 deletions(-) diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 17d2cc1fc..565c5f81f 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -25,6 +25,7 @@ from typing import ( Generic, Literal, NoReturn, + TypeVar, final, overload, ) @@ -186,6 +187,8 @@ from pandas.core.dtypes.dtypes import CategoricalDtype from pandas.plotting import PlotAccessor +_T_COMPLEX = TypeVar("_T_COMPLEX", bound=complex) + class _iLocIndexerSeries(_iLocIndexer, Generic[S1]): # get item @overload @@ -1616,8 +1619,34 @@ class Series(IndexOpsMixin[S1], NDFrame): # them up. @overload def __add__( - self: Series[int], other: int | Sequence[int] | Series[int] - ) -> Series[int]: ... + self: Series[Never], + other: num | _str | timedelta | Timedelta | _ListLike | Series | np.timedelta64, + ) -> Series: ... + @overload + def __add__(self: Series[int], other: Series[Never]) -> Series: ... + @overload + def __add__( + self: Series[int], other: _T_COMPLEX | Sequence[_T_COMPLEX] | Series[_T_COMPLEX] + ) -> Series[_T_COMPLEX]: ... + @overload + def __add__(self: Series[int], other: np_ndarray_anyint) -> Series[int]: ... + @overload + def __add__(self: Series[int], other: np_ndarray_float) -> Series[float]: ... + @overload + def __add__(self: Series[int], other: np_ndarray_complex) -> Series[complex]: ... + @overload + def __add__(self: Series[float], other: Series[Never]) -> Series: ... + @overload + def __add__( + self: Series[float], + other: int | Sequence[int] | np_ndarray_anyint | Series[int], + ) -> Series[float]: ... + @overload + def __add__(self: Series[complex], other: Series[Never]) -> Series: ... + @overload + def __add__( + self: Series[complex], other: int | Sequence[int] | Series[int] + ) -> Series[complex]: ... @overload def __add__(self, other: S1 | Self) -> Self: ... @overload @@ -1665,6 +1694,14 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __or__(self, other: int | np_ndarray_anyint | Series[int]) -> Series[int]: ... @overload + def __radd__( + self: Series[Never], other: num | _str | _ListLike | Series + ) -> Series: ... + @overload + def __radd__( + self: Series[int], other: _T_COMPLEX | Sequence[_T_COMPLEX] + ) -> Series[_T_COMPLEX]: ... + @overload def __radd__(self, other: S1 | Series[S1]) -> Self: ... @overload def __radd__(self, other: num | _str | _ListLike | Series) -> Series: ... @@ -1743,19 +1780,60 @@ class Series(IndexOpsMixin[S1], NDFrame): @property def loc(self) -> _LocIndexerSeries[S1]: ... # Methods + @overload def add( - self, + self: Series[Never], other: ( - Sequence[S1] + Sequence | np_ndarray_anyint | np_ndarray_float | np_ndarray_complex - | Series[S1] + | Series | Scalar ), level: Level | None = ..., fill_value: float | None = ..., axis: int = ..., + ) -> Series: ... + @overload + def add( + self: Series[int], + other: _T_COMPLEX | Sequence[_T_COMPLEX] | Series[_T_COMPLEX], + level: Level | None = ..., + fill_value: float | None = ..., + axis: int = ..., + ) -> Series[_T_COMPLEX]: ... + @overload + def add( + self: Series[int], + other: np_ndarray_anyint, + level: Level | None = ..., + fill_value: float | None = ..., + axis: int = ..., + ) -> Series[int]: ... + @overload + def add( + self: Series[int], + other: np_ndarray_float, + level: Level | None = ..., + fill_value: float | None = ..., + axis: int = ..., + ) -> Series[float]: ... + @overload + def add( + self: Series[int], + other: np_ndarray_complex, + level: Level | None = ..., + fill_value: float | None = ..., + axis: int = ..., + ) -> Series[complex]: ... + @overload + def add( + self, + other: Series[S1] | Scalar, + level: Level | None = ..., + fill_value: float | None = ..., + axis: int = ..., ) -> Series[S1]: ... def all( self, @@ -1996,19 +2074,60 @@ class Series(IndexOpsMixin[S1], NDFrame): min_count: int = ..., **kwargs: Any, ) -> Scalar: ... + @overload def radd( - self, + self: Series[Never], other: ( - Sequence[S1] + Sequence | np_ndarray_anyint | np_ndarray_float | np_ndarray_complex - | Series[S1] + | Series | Scalar ), level: Level | None = ..., fill_value: float | None = ..., axis: AxisIndex = ..., + ) -> Series: ... + @overload + def radd( + self: Series[int], + other: _T_COMPLEX | Sequence[_T_COMPLEX] | Series[_T_COMPLEX], + level: Level | None = ..., + fill_value: float | None = ..., + axis: int = ..., + ) -> Series[_T_COMPLEX]: ... + @overload + def radd( + self: Series[int], + other: np_ndarray_anyint, + level: Level | None = ..., + fill_value: float | None = ..., + axis: int = ..., + ) -> Series[int]: ... + @overload + def radd( + self: Series[int], + other: np_ndarray_float, + level: Level | None = ..., + fill_value: float | None = ..., + axis: int = ..., + ) -> Series[float]: ... + @overload + def radd( + self: Series[int], + other: np_ndarray_complex, + level: Level | None = ..., + fill_value: float | None = ..., + axis: int = ..., + ) -> Series[complex]: ... + @overload + def radd( + self, + other: Series[S1] | Scalar, + level: Level | None = ..., + fill_value: float | None = ..., + axis: AxisIndex = ..., ) -> Series[S1]: ... def rdivmod( self, diff --git a/tests/series/arithmetic/int/test_add.py b/tests/series/arithmetic/int/test_add.py index 1b6b75ced..7407444dc 100644 --- a/tests/series/arithmetic/int/test_add.py +++ b/tests/series/arithmetic/int/test_add.py @@ -1,5 +1,6 @@ from typing import assert_type +import numpy as np import pandas as pd from tests import check @@ -11,94 +12,85 @@ def test_add_py_scalar() -> None: """Test pd.Series[int] + Python native scalars""" i, f, c = 1, 1.0, 1j - check(assert_type(left + i, "pd.Series[int]"), pd.Series, int) - # check(assert_type(left + f, "pd.Series[float]"), pd.Series, float) - # check(assert_type(left + c, "pd.Series[complex]"), pd.Series, complex) + check(assert_type(left + i, "pd.Series[int]"), pd.Series, np.int64) + check(assert_type(left + f, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left + c, "pd.Series[complex]"), pd.Series, np.complex128) - check(assert_type(i + left, "pd.Series[int]"), pd.Series, int) - # check(assert_type(f + left, "pd.Series[float]"), pd.Series, float) - # check(assert_type(c + left, "pd.Series[complex]"), pd.Series, complex) + check(assert_type(i + left, "pd.Series[int]"), pd.Series, np.int64) + check(assert_type(f + left, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(c + left, "pd.Series[complex]"), pd.Series, np.complex128) - check(assert_type(left.add(i), "pd.Series[int]"), pd.Series, int) - # check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, float) - # check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, complex) + check(assert_type(left.add(i), "pd.Series[int]"), pd.Series, np.int64) + check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, np.complex128) - check(assert_type(left.radd(i), "pd.Series[int]"), pd.Series, int) - - -# check(assert_type(left.radd(f), "pd.Series[float]"), pd.Series, float) -# check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, complex) + check(assert_type(left.radd(i), "pd.Series[int]"), pd.Series, np.int64) + check(assert_type(left.radd(f), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, np.complex128) def test_add_py_sequence() -> None: """Test pd.Series[int] + Python native sequence""" i, f, c = [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] - check(assert_type(left + i, "pd.Series[int]"), pd.Series, int) - # check(assert_type(left + f, "pd.Series[float]"), pd.Series, float) - # check(assert_type(left + c, "pd.Series[complex]"), pd.Series, complex) - - # check(assert_type(i + left, "pd.Series[int]"), pd.Series, int) - # check(assert_type(f + left, "pd.Series[float]"), pd.Series, float) - # check(assert_type(c + left, "pd.Series[complex]"), pd.Series, complex) + check(assert_type(left + i, "pd.Series[int]"), pd.Series, np.int64) + check(assert_type(left + f, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left + c, "pd.Series[complex]"), pd.Series, np.complex128) - check(assert_type(left.add(i), "pd.Series[int]"), pd.Series, int) + check(assert_type(i + left, "pd.Series[int]"), pd.Series, np.int64) + check(assert_type(f + left, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(c + left, "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.add(i), "pd.Series[int]"), pd.Series, np.int64) + check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, np.complex128) -# check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, float) -# check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, complex) + check(assert_type(left.radd(i), "pd.Series[int]"), pd.Series, np.int64) + check(assert_type(left.radd(f), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, np.complex128) -# check(assert_type(left.radd(i), "pd.Series[int]"), pd.Series, int) -# check(assert_type(left.radd(f), "pd.Series[int]"), pd.Series, int) -# check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, complex) +def test_add_numpy_array() -> None: + """Test pd.Series[int] + numpy array""" + i = np.array([2, 3, 5], np.int64) + f = np.array([1.0, 2.0, 3.0], np.float64) + c = np.array([1.1j, 2.2j, 4.1j], np.complex128) -# def test_add_numpy_array() -> None: -# """Test pd.Series[int] + numpy array""" -# i = np.array([2, 3, 5], np.int64) -# f = np.array([1.0, 2.0, 3.0], np.float64) -# c = np.array([1.1j, 2.2j, 4.1j], np.complex64) + check(assert_type(left + i, "pd.Series[int]"), pd.Series, np.int64) + check(assert_type(left + f, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left + c, "pd.Series[complex]"), pd.Series, np.complex128) -# check(assert_type(left + i, "pd.Series[int]"), pd.Series, int) -# check(assert_type(left + f, "pd.Series[float]"), pd.Series, float) -# check(assert_type(left + c, "pd.Series[complex]"), pd.Series, complex) + # check(assert_type(i + l, "pd.Series[int]"), pd.Series, np.int64) + # check(assert_type(f + l, "pd.Series[float]"), pd.Series, np.float64) + # check(assert_type(c + l, "pd.Series[complex]"), pd.Series, np.complex128) -# # check(assert_type(i + l, "pd.Series[int]"), pd.Series, int) -# # check(assert_type(f + l, "pd.Series[float]"), pd.Series, float) -# # check(assert_type(c + l, "pd.Series[complex]"), pd.Series, complex) + check(assert_type(left.add(i), "pd.Series[int]"), pd.Series, np.int64) + check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, np.complex128) -# check(assert_type(left.add(i), "pd.Series[int]"), pd.Series, int) -# check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, float) -# check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, complex) - -# check(assert_type(left.radd(i), "pd.Series[int]"), pd.Series, int) -# check(assert_type(left.radd(f), "pd.Series[float]"), pd.Series, float) -# check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, complex) + check(assert_type(left.radd(i), "pd.Series[int]"), pd.Series, np.int64) + check(assert_type(left.radd(f), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, np.complex128) def test_add_pd_series() -> None: """Test pd.Series[int] + pandas series""" i = pd.Series([2, 3, 5]) - # f = pd.Series([1.0, 2.0, 3.0]) - # c = pd.Series([1.1j, 2.2j, 4.1j]) - - check(assert_type(left + i, "pd.Series[int]"), pd.Series, int) - # check(assert_type(left + f, "pd.Series[float]"), pd.Series, float) - # check(assert_type(left + c, "pd.Series[complex]"), pd.Series, complex) - - # check( - # assert_type(i + left, pd.Series), "pd.Series[int]"), pd.Series, int) - # check( - # assert_type(f + left, "pd.Series[float]"), pd.Series, float) - # check( - # assert_type(c + left, pd.Series), "pd.Series[complex]"), pd.Series, complex) + f = pd.Series([1.0, 2.0, 3.0]) + c = pd.Series([1.1j, 2.2j, 4.1j]) - check(assert_type(left.add(i), "pd.Series[int]"), pd.Series, int) - # check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, float) - # check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, complex) + check(assert_type(left + i, "pd.Series[int]"), pd.Series, np.int64) + check(assert_type(left + f, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left + c, "pd.Series[complex]"), pd.Series, np.complex128) - check(assert_type(left.radd(i), "pd.Series[int]"), pd.Series, int) + check(assert_type(i + left, "pd.Series[int]"), pd.Series, np.int64) + check(assert_type(f + left, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(c + left, "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.add(i), "pd.Series[int]"), pd.Series, np.int64) + check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, np.complex128) -# check(assert_type(left.radd(f), "pd.Series[float]"), pd.Series, float) -# check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, complex) + check(assert_type(left.radd(i), "pd.Series[int]"), pd.Series, np.int64) + check(assert_type(left.radd(f), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, np.complex128) diff --git a/tests/series/arithmetic/test_add.py b/tests/series/arithmetic/test_add.py index 2d2c5916a..e833fb053 100644 --- a/tests/series/arithmetic/test_add.py +++ b/tests/series/arithmetic/test_add.py @@ -79,22 +79,13 @@ def test_add_pd_series() -> None: f = pd.Series([1.0, 2.0, 3.0]) c = pd.Series([1.1j, 2.2j, 4.1j]) - # check(assert_type(left + i, pd.Series), pd.Series) # why? + check(assert_type(left + i, pd.Series), pd.Series) check(assert_type(left + f, pd.Series), pd.Series) check(assert_type(left + c, pd.Series), pd.Series) - check( - assert_type(i + left, pd.Series), # pyright: ignore[reportAssertTypeFailure] - pd.Series, - ) - check( - assert_type(f + left, pd.Series), # pyright: ignore[reportAssertTypeFailure] - pd.Series, - ) - check( - assert_type(c + left, pd.Series), # pyright: ignore[reportAssertTypeFailure] - pd.Series, - ) + check(assert_type(i + left, pd.Series), pd.Series) + check(assert_type(f + left, pd.Series), pd.Series) + check(assert_type(c + left, pd.Series), pd.Series) check(assert_type(left.add(i), pd.Series), pd.Series) check(assert_type(left.add(f), pd.Series), pd.Series) diff --git a/tests/series/test_series.py b/tests/series/test_series.py index fdfe7f09b..4b6b4b9d8 100644 --- a/tests/series/test_series.py +++ b/tests/series/test_series.py @@ -1599,10 +1599,7 @@ def test_series_min_max_sub_axis() -> None: ss = s1 - s2 sm = s1 * s2 sd = s1 / s2 - check( - assert_type(sa, pd.Series), # pyright: ignore[reportAssertTypeFailure] # why? - pd.Series, - ) + check(assert_type(sa, pd.Series), pd.Series) check(assert_type(ss, pd.Series), pd.Series) check(assert_type(sm, pd.Series), pd.Series) check(assert_type(sd, pd.Series), pd.Series) diff --git a/tests/test_frame.py b/tests/test_frame.py index b4d33fc1c..ffd85d609 100644 --- a/tests/test_frame.py +++ b/tests/test_frame.py @@ -2819,25 +2819,9 @@ def test_sum_get_add() -> None: summer = df.sum(axis=1) check(assert_type(summer, pd.Series), pd.Series) - check( - assert_type( - s + summer, pd.Series # pyright: ignore[reportAssertTypeFailure] # why? - ), - pd.Series, - ) - check( - assert_type( - s + df["y"], pd.Series # pyright: ignore[reportAssertTypeFailure] # why? - ), - pd.Series, - ) - check( - assert_type( - summer + summer, # pyright: ignore[reportAssertTypeFailure] # why? - pd.Series, - ), - pd.Series, - ) + check(assert_type(s + summer, pd.Series), pd.Series) + check(assert_type(s + df["y"], pd.Series), pd.Series) + check(assert_type(summer + summer, pd.Series), pd.Series) def test_getset_untyped() -> None: From 710affe94603cf10d38c4ad70efbf54e3430eebf Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 15 Jul 2025 17:03:18 +0200 Subject: [PATCH 3/8] feat: Series[float] + --- pandas-stubs/core/series.pyi | 66 +++++++++++++++- tests/series/arithmetic/float/__init__.py | 0 tests/series/arithmetic/float/test_add.py | 96 +++++++++++++++++++++++ 3 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 tests/series/arithmetic/float/__init__.py create mode 100644 tests/series/arithmetic/float/test_add.py diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 565c5f81f..ded6c3ed0 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -1639,13 +1639,21 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __add__( self: Series[float], - other: int | Sequence[int] | np_ndarray_anyint | Series[int], + other: int | Sequence[int] | np_ndarray_anyint | np_ndarray_float | Series[int], ) -> Series[float]: ... @overload + def __add__( + self: Series[float], + other: _T_COMPLEX | Sequence[_T_COMPLEX] | Series[_T_COMPLEX], + ) -> Series[_T_COMPLEX]: ... + @overload + def __add__(self: Series[float], other: np_ndarray_complex) -> Series[complex]: ... + @overload def __add__(self: Series[complex], other: Series[Never]) -> Series: ... @overload def __add__( - self: Series[complex], other: int | Sequence[int] | Series[int] + self: Series[complex], + other: _T_COMPLEX | Sequence[_T_COMPLEX] | Series[_T_COMPLEX], ) -> Series[complex]: ... @overload def __add__(self, other: S1 | Self) -> Self: ... @@ -1702,6 +1710,12 @@ class Series(IndexOpsMixin[S1], NDFrame): self: Series[int], other: _T_COMPLEX | Sequence[_T_COMPLEX] ) -> Series[_T_COMPLEX]: ... @overload + def __radd__(self: Series[float], other: int | Sequence[int]) -> Series[float]: ... + @overload + def __radd__( + self: Series[float], other: _T_COMPLEX | Sequence[_T_COMPLEX] + ) -> Series[_T_COMPLEX]: ... + @overload def __radd__(self, other: S1 | Series[S1]) -> Self: ... @overload def __radd__(self, other: num | _str | _ListLike | Series) -> Series: ... @@ -1828,6 +1842,30 @@ class Series(IndexOpsMixin[S1], NDFrame): axis: int = ..., ) -> Series[complex]: ... @overload + def add( + self: Series[float], + other: int | Sequence[int] | np_ndarray_anyint | np_ndarray_float | Series[int], + level: Level | None = ..., + fill_value: float | None = ..., + axis: int = ..., + ) -> Series[float]: ... + @overload + def add( + self: Series[float], + other: _T_COMPLEX | Sequence[_T_COMPLEX] | Series[_T_COMPLEX], + level: Level | None = ..., + fill_value: float | None = ..., + axis: int = ..., + ) -> Series[_T_COMPLEX]: ... + @overload + def add( + self: Series[float], + other: np_ndarray_complex, + level: Level | None = ..., + fill_value: float | None = ..., + axis: int = ..., + ) -> Series[complex]: ... + @overload def add( self, other: Series[S1] | Scalar, @@ -2122,6 +2160,30 @@ class Series(IndexOpsMixin[S1], NDFrame): axis: int = ..., ) -> Series[complex]: ... @overload + def radd( + self: Series[float], + other: int | Sequence[int] | np_ndarray_anyint | np_ndarray_float | Series[int], + level: Level | None = ..., + fill_value: float | None = ..., + axis: int = ..., + ) -> Series[float]: ... + @overload + def radd( + self: Series[float], + other: _T_COMPLEX | Sequence[_T_COMPLEX] | Series[_T_COMPLEX], + level: Level | None = ..., + fill_value: float | None = ..., + axis: int = ..., + ) -> Series[_T_COMPLEX]: ... + @overload + def radd( + self: Series[float], + other: np_ndarray_complex, + level: Level | None = ..., + fill_value: float | None = ..., + axis: int = ..., + ) -> Series[complex]: ... + @overload def radd( self, other: Series[S1] | Scalar, diff --git a/tests/series/arithmetic/float/__init__.py b/tests/series/arithmetic/float/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/series/arithmetic/float/test_add.py b/tests/series/arithmetic/float/test_add.py new file mode 100644 index 000000000..b5651e022 --- /dev/null +++ b/tests/series/arithmetic/float/test_add.py @@ -0,0 +1,96 @@ +from typing import assert_type + +import numpy as np +import pandas as pd + +from tests import check + +left = pd.Series([1.0, 2.0, 3.0]) # left operand + + +def test_add_py_scalar() -> None: + """Test pd.Series[float] + Python native scalars""" + i, f, c = 1, 1.0, 1j + + check(assert_type(left + i, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left + f, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left + c, "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(i + left, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(f + left, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(c + left, "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(left.add(i), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(left.radd(i), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.radd(f), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, np.complex128) + + +def test_add_py_sequence() -> None: + """Test pd.Series[float] + Python native sequence""" + i, f, c = [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] + + check(assert_type(left + i, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left + f, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left + c, "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(i + left, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(f + left, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(c + left, "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(left.add(i), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(left.radd(i), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.radd(f), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, np.complex128) + + +def test_add_numpy_array() -> None: + """Test pd.Series[float] + numpy array""" + i = np.array([2, 3, 5], np.int64) + f = np.array([1.0, 2.0, 3.0], np.float64) + c = np.array([1.1j, 2.2j, 4.1j], np.complex128) + + check(assert_type(left + i, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left + f, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left + c, "pd.Series[complex]"), pd.Series, np.complex128) + + # check(assert_type(i + l, "pd.Series[float]"), pd.Series, np.float64) + # check(assert_type(f + l, "pd.Series[float]"), pd.Series, np.float64) + # check(assert_type(c + l, "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(left.add(i), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(left.radd(i), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.radd(f), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, np.complex128) + + +def test_add_pd_series() -> None: + """Test pd.Series[float] + pandas series""" + i = pd.Series([2, 3, 5]) + f = pd.Series([1.0, 2.0, 3.0]) + c = pd.Series([1.1j, 2.2j, 4.1j]) + + check(assert_type(left + i, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left + f, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left + c, "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(i + left, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(f + left, "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(c + left, "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(left.add(i), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(left.radd(i), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.radd(f), "pd.Series[float]"), pd.Series, np.float64) + check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, np.complex128) From 7a5cbdbc9d7a1ffa99ba57c3c365a3cb1fab500d Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 15 Jul 2025 17:14:12 +0200 Subject: [PATCH 4/8] refactor: py310 and remove why --- tests/series/arithmetic/float/test_add.py | 3 +-- tests/series/arithmetic/int/test_add.py | 3 +-- tests/series/arithmetic/test_add.py | 7 +++---- tests/series/test_series.py | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/tests/series/arithmetic/float/test_add.py b/tests/series/arithmetic/float/test_add.py index b5651e022..4ecdd744c 100644 --- a/tests/series/arithmetic/float/test_add.py +++ b/tests/series/arithmetic/float/test_add.py @@ -1,7 +1,6 @@ -from typing import assert_type - import numpy as np import pandas as pd +from typing_extensions import assert_type from tests import check diff --git a/tests/series/arithmetic/int/test_add.py b/tests/series/arithmetic/int/test_add.py index 7407444dc..bb4aec791 100644 --- a/tests/series/arithmetic/int/test_add.py +++ b/tests/series/arithmetic/int/test_add.py @@ -1,7 +1,6 @@ -from typing import assert_type - import numpy as np import pandas as pd +from typing_extensions import assert_type from tests import check diff --git a/tests/series/arithmetic/test_add.py b/tests/series/arithmetic/test_add.py index e833fb053..e1d054d25 100644 --- a/tests/series/arithmetic/test_add.py +++ b/tests/series/arithmetic/test_add.py @@ -1,7 +1,6 @@ -from typing import assert_type - import numpy as np import pandas as pd +from typing_extensions import assert_type from tests import check @@ -12,7 +11,7 @@ def test_add_py_scalar() -> None: """Test pd.Series[Any] + Python native scalars""" i, f, c = 1, 1.0, 1j - # check(assert_type(left + i, pd.Series), pd.Series) # why? + check(assert_type(left + i, pd.Series), pd.Series) check(assert_type(left + f, pd.Series), pd.Series) check(assert_type(left + c, pd.Series), pd.Series) @@ -33,7 +32,7 @@ def test_add_py_sequence() -> None: """Test pd.Series[Any] + Python native sequence""" i, f, c = [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] - # check(assert_type(left + i, pd.Series), pd.Series) # why? + check(assert_type(left + i, pd.Series), pd.Series) check(assert_type(left + f, pd.Series), pd.Series) check(assert_type(left + c, pd.Series), pd.Series) diff --git a/tests/series/test_series.py b/tests/series/test_series.py index 4b6b4b9d8..1e48aae75 100644 --- a/tests/series/test_series.py +++ b/tests/series/test_series.py @@ -3892,7 +3892,7 @@ def foo(sf: pd.Series) -> None: pass foo(s) - # check(assert_type(s + pd.Series([1]), pd.Series), pd.Series) # why? + check(assert_type(s + pd.Series([1]), pd.Series), pd.Series) def test_series_items() -> None: From d5b2cf9e2a306322340f975e156c23266574b2ca Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 15 Jul 2025 18:56:50 +0200 Subject: [PATCH 5/8] feat: Series[complex] + --- pandas-stubs/core/series.pyi | 41 ++++++++- tests/series/arithmetic/complex/__init__.py | 0 tests/series/arithmetic/complex/test_add.py | 95 +++++++++++++++++++++ 3 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 tests/series/arithmetic/complex/__init__.py create mode 100644 tests/series/arithmetic/complex/test_add.py diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index ded6c3ed0..34c8f5986 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -1653,7 +1653,14 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __add__( self: Series[complex], - other: _T_COMPLEX | Sequence[_T_COMPLEX] | Series[_T_COMPLEX], + other: ( + _T_COMPLEX + | Sequence[_T_COMPLEX] + | Series[_T_COMPLEX] + | np_ndarray_anyint + | np_ndarray_float + | np_ndarray_complex + ), ) -> Series[complex]: ... @overload def __add__(self, other: S1 | Self) -> Self: ... @@ -1716,6 +1723,10 @@ class Series(IndexOpsMixin[S1], NDFrame): self: Series[float], other: _T_COMPLEX | Sequence[_T_COMPLEX] ) -> Series[_T_COMPLEX]: ... @overload + def __radd__( + self: Series[complex], other: _T_COMPLEX | Sequence[_T_COMPLEX] + ) -> Series[complex]: ... + @overload def __radd__(self, other: S1 | Series[S1]) -> Self: ... @overload def __radd__(self, other: num | _str | _ListLike | Series) -> Series: ... @@ -1866,6 +1877,20 @@ class Series(IndexOpsMixin[S1], NDFrame): axis: int = ..., ) -> Series[complex]: ... @overload + def add( + self: Series[complex], + other: ( + Sequence[_T_COMPLEX] + | np_ndarray_anyint + | np_ndarray_float + | np_ndarray_complex + | Series[_T_COMPLEX] + ), + level: Level | None = ..., + fill_value: float | None = ..., + axis: int = ..., + ) -> Series[complex]: ... + @overload def add( self, other: Series[S1] | Scalar, @@ -2184,6 +2209,20 @@ class Series(IndexOpsMixin[S1], NDFrame): axis: int = ..., ) -> Series[complex]: ... @overload + def radd( + self: Series[complex], + other: ( + Sequence[_T_COMPLEX] + | np_ndarray_anyint + | np_ndarray_float + | np_ndarray_complex + | Series[_T_COMPLEX] + ), + level: Level | None = ..., + fill_value: float | None = ..., + axis: int = ..., + ) -> Series[complex]: ... + @overload def radd( self, other: Series[S1] | Scalar, diff --git a/tests/series/arithmetic/complex/__init__.py b/tests/series/arithmetic/complex/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/series/arithmetic/complex/test_add.py b/tests/series/arithmetic/complex/test_add.py new file mode 100644 index 000000000..3b0f910bf --- /dev/null +++ b/tests/series/arithmetic/complex/test_add.py @@ -0,0 +1,95 @@ +import numpy as np +import pandas as pd +from typing_extensions import assert_type + +from tests import check + +left = pd.Series([1j, 2j, 3j]) # left operand + + +def test_add_py_scalar() -> None: + """Test pd.Series[complex] + Python native scalars""" + i, f, c = 1, 1.0, 1j + + check(assert_type(left + i, "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left + f, "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left + c, "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(i + left, "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(f + left, "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(c + left, "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(left.add(i), "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.add(f), "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(left.radd(i), "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.radd(f), "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, np.complex128) + + +def test_add_py_sequence() -> None: + """Test pd.Series[complex] + Python native sequence""" + i, f, c = [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] + + check(assert_type(left + i, "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left + f, "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left + c, "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(i + left, "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(f + left, "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(c + left, "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(left.add(i), "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.add(f), "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(left.radd(i), "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.radd(f), "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, np.complex128) + + +def test_add_numpy_array() -> None: + """Test pd.Series[complex] + numpy array""" + i = np.array([2, 3, 5], np.int64) + f = np.array([1.0, 2.0, 3.0], np.float64) + c = np.array([1.1j, 2.2j, 4.1j], np.complex128) + + check(assert_type(left + i, "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left + f, "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left + c, "pd.Series[complex]"), pd.Series, np.complex128) + + # check(assert_type(i + l, "pd.Series[complex]"), pd.Series, np.complex128) + # check(assert_type(f + l, "pd.Series[complex]"), pd.Series, np.complex128) + # check(assert_type(c + l, "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(left.add(i), "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.add(f), "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(left.radd(i), "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.radd(f), "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, np.complex128) + + +def test_add_pd_series() -> None: + """Test pd.Series[complex] + pandas series""" + i = pd.Series([2, 3, 5]) + f = pd.Series([1.0, 2.0, 3.0]) + c = pd.Series([1.1j, 2.2j, 4.1j]) + + check(assert_type(left + i, "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left + f, "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left + c, "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(i + left, "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(f + left, "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(c + left, "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(left.add(i), "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.add(f), "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.add(c), "pd.Series[complex]"), pd.Series, np.complex128) + + check(assert_type(left.radd(i), "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.radd(f), "pd.Series[complex]"), pd.Series, np.complex128) + check(assert_type(left.radd(c), "pd.Series[complex]"), pd.Series, np.complex128) From 8d5c397c194f47db30cd17887b619ba77e9ffff6 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 16 Jul 2025 22:05:59 +0200 Subject: [PATCH 6/8] fix(comment): https://github.com/pandas-dev/pandas-stubs/pull/1275#discussion_r2211363732 --- pandas-stubs/core/series.pyi | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 34c8f5986..57fb1a993 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -1623,7 +1623,7 @@ class Series(IndexOpsMixin[S1], NDFrame): other: num | _str | timedelta | Timedelta | _ListLike | Series | np.timedelta64, ) -> Series: ... @overload - def __add__(self: Series[int], other: Series[Never]) -> Series: ... + def __add__(self: Series, other: Series[Never]) -> Series: ... @overload def __add__( self: Series[int], other: _T_COMPLEX | Sequence[_T_COMPLEX] | Series[_T_COMPLEX] @@ -1635,8 +1635,6 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __add__(self: Series[int], other: np_ndarray_complex) -> Series[complex]: ... @overload - def __add__(self: Series[float], other: Series[Never]) -> Series: ... - @overload def __add__( self: Series[float], other: int | Sequence[int] | np_ndarray_anyint | np_ndarray_float | Series[int], @@ -1649,8 +1647,6 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __add__(self: Series[float], other: np_ndarray_complex) -> Series[complex]: ... @overload - def __add__(self: Series[complex], other: Series[Never]) -> Series: ... - @overload def __add__( self: Series[complex], other: ( From 6ea5eb88cdbfd6cf1ff30fa689d97f7d1bbdd38d Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 16 Jul 2025 22:59:24 +0200 Subject: [PATCH 7/8] fix(comment): https://github.com/pandas-dev/pandas-stubs/pull/1275/files#r2211559024 --- pandas-stubs/core/series.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 57fb1a993..cfb5f7e6c 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -1720,7 +1720,7 @@ class Series(IndexOpsMixin[S1], NDFrame): ) -> Series[_T_COMPLEX]: ... @overload def __radd__( - self: Series[complex], other: _T_COMPLEX | Sequence[_T_COMPLEX] + self: Series[complex], other: complex | Sequence[complex] ) -> Series[complex]: ... @overload def __radd__(self, other: S1 | Series[S1]) -> Self: ... From 2b94ab00272413dbbee29db2209293a3914c3b0c Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 16 Jul 2025 23:20:05 +0200 Subject: [PATCH 8/8] fix(comment): https://github.com/pandas-dev/pandas-stubs/pull/1275/files#r2211571551 --- tests/series/arithmetic/complex/test_add.py | 25 ++++++++++++++++++--- tests/series/arithmetic/float/test_add.py | 25 ++++++++++++++++++--- tests/series/arithmetic/int/test_add.py | 25 ++++++++++++++++++--- tests/series/arithmetic/test_add.py | 22 +++++++++++++++--- 4 files changed, 85 insertions(+), 12 deletions(-) diff --git a/tests/series/arithmetic/complex/test_add.py b/tests/series/arithmetic/complex/test_add.py index 3b0f910bf..5c43763e0 100644 --- a/tests/series/arithmetic/complex/test_add.py +++ b/tests/series/arithmetic/complex/test_add.py @@ -59,9 +59,28 @@ def test_add_numpy_array() -> None: check(assert_type(left + f, "pd.Series[complex]"), pd.Series, np.complex128) check(assert_type(left + c, "pd.Series[complex]"), pd.Series, np.complex128) - # check(assert_type(i + l, "pd.Series[complex]"), pd.Series, np.complex128) - # check(assert_type(f + l, "pd.Series[complex]"), pd.Series, np.complex128) - # check(assert_type(c + l, "pd.Series[complex]"), pd.Series, np.complex128) + # numpy typing gives ndarray instead of `pd.Series[...]` in reality, which we cannot fix + check( + assert_type( # type: ignore[assert-type] + i + left, "pd.Series[complex]" # pyright: ignore[reportAssertTypeFailure] + ), + pd.Series, + np.complex128, + ) + check( + assert_type( # type: ignore[assert-type] + f + left, "pd.Series[complex]" # pyright: ignore[reportAssertTypeFailure] + ), + pd.Series, + np.complex128, + ) + check( + assert_type( # type: ignore[assert-type] + c + left, "pd.Series[complex]" # pyright: ignore[reportAssertTypeFailure] + ), + pd.Series, + np.complex128, + ) check(assert_type(left.add(i), "pd.Series[complex]"), pd.Series, np.complex128) check(assert_type(left.add(f), "pd.Series[complex]"), pd.Series, np.complex128) diff --git a/tests/series/arithmetic/float/test_add.py b/tests/series/arithmetic/float/test_add.py index 4ecdd744c..16085f366 100644 --- a/tests/series/arithmetic/float/test_add.py +++ b/tests/series/arithmetic/float/test_add.py @@ -59,9 +59,28 @@ def test_add_numpy_array() -> None: check(assert_type(left + f, "pd.Series[float]"), pd.Series, np.float64) check(assert_type(left + c, "pd.Series[complex]"), pd.Series, np.complex128) - # check(assert_type(i + l, "pd.Series[float]"), pd.Series, np.float64) - # check(assert_type(f + l, "pd.Series[float]"), pd.Series, np.float64) - # check(assert_type(c + l, "pd.Series[complex]"), pd.Series, np.complex128) + # numpy typing gives ndarray instead of `pd.Series[...]` in reality, which we cannot fix + check( + assert_type( # type: ignore[assert-type] + i + left, "pd.Series[float]" # pyright: ignore[reportAssertTypeFailure] + ), + pd.Series, + np.float64, + ) + check( + assert_type( # type: ignore[assert-type] + f + left, "pd.Series[float]" # pyright: ignore[reportAssertTypeFailure] + ), + pd.Series, + np.float64, + ) + check( + assert_type( # type: ignore[assert-type] + c + left, "pd.Series[complex]" # pyright: ignore[reportAssertTypeFailure] + ), + pd.Series, + np.complex128, + ) check(assert_type(left.add(i), "pd.Series[float]"), pd.Series, np.float64) check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, np.float64) diff --git a/tests/series/arithmetic/int/test_add.py b/tests/series/arithmetic/int/test_add.py index bb4aec791..cb78181c6 100644 --- a/tests/series/arithmetic/int/test_add.py +++ b/tests/series/arithmetic/int/test_add.py @@ -59,9 +59,28 @@ def test_add_numpy_array() -> None: check(assert_type(left + f, "pd.Series[float]"), pd.Series, np.float64) check(assert_type(left + c, "pd.Series[complex]"), pd.Series, np.complex128) - # check(assert_type(i + l, "pd.Series[int]"), pd.Series, np.int64) - # check(assert_type(f + l, "pd.Series[float]"), pd.Series, np.float64) - # check(assert_type(c + l, "pd.Series[complex]"), pd.Series, np.complex128) + # numpy typing gives ndarray instead of `pd.Series[...]` in reality, which we cannot fix + check( + assert_type( # type: ignore[assert-type] + i + left, "pd.Series[int]" # pyright: ignore[reportAssertTypeFailure] + ), + pd.Series, + np.int64, + ) + check( + assert_type( # type: ignore[assert-type] + f + left, "pd.Series[float]" # pyright: ignore[reportAssertTypeFailure] + ), + pd.Series, + np.float64, + ) + check( + assert_type( # type: ignore[assert-type] + c + left, "pd.Series[complex]" # pyright: ignore[reportAssertTypeFailure] + ), + pd.Series, + np.complex128, + ) check(assert_type(left.add(i), "pd.Series[int]"), pd.Series, np.int64) check(assert_type(left.add(f), "pd.Series[float]"), pd.Series, np.float64) diff --git a/tests/series/arithmetic/test_add.py b/tests/series/arithmetic/test_add.py index e1d054d25..0001f6ec7 100644 --- a/tests/series/arithmetic/test_add.py +++ b/tests/series/arithmetic/test_add.py @@ -59,9 +59,25 @@ def test_add_numpy_array() -> None: check(assert_type(left + f, pd.Series), pd.Series) check(assert_type(left + c, pd.Series), pd.Series) - # check(assert_type(i + l, pd.Series), pd.Series) - # check(assert_type(f + l, pd.Series), pd.Series) - # check(assert_type(c + l, pd.Series), pd.Series) + # numpy typing gives ndarray instead of `pd.Series[...]` in reality, which we cannot fix + check( + assert_type( # type: ignore[assert-type] + i + left, pd.Series # pyright: ignore[reportAssertTypeFailure] + ), + pd.Series, + ) + check( + assert_type( # type: ignore[assert-type] + f + left, pd.Series # pyright: ignore[reportAssertTypeFailure] + ), + pd.Series, + ) + check( + assert_type( # type: ignore[assert-type] + c + left, pd.Series # pyright: ignore[reportAssertTypeFailure] + ), + pd.Series, + ) check(assert_type(left.add(i), pd.Series), pd.Series) check(assert_type(left.add(f), pd.Series), pd.Series)