From b6cdcf12ca65abcc5809497bb0b1cfabd624b88a Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Fri, 22 Aug 2025 09:13:14 +0200 Subject: [PATCH 1/7] fix(series): arithmetics for Series[Any] --- pandas-stubs/core/series.pyi | 18 +- tests/series/arithmetic/str/test_add.py | 8 +- tests/series/arithmetic/test_add.py | 157 +++++++++-------- tests/series/arithmetic/test_mul.py | 149 ++++++++-------- tests/series/arithmetic/test_sub.py | 93 ++++++---- tests/series/arithmetic/test_truediv.py | 219 ++++++++++++------------ tests/series/test_series.py | 43 ++--- 7 files changed, 356 insertions(+), 331 deletions(-) diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index f5bea7bf..938360a4 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -2705,13 +2705,9 @@ class Series(IndexOpsMixin[S1], NDFrame): axis: int = 0, ) -> TimedeltaSeries: ... @overload - def __rsub__( # type: ignore[misc] + def __rsub__( # type: ignore[overload-overlap] self: Series[Never], - other: datetime | np.datetime64 | np_ndarray_dt | TimestampSeries, - ) -> TimedeltaSeries: ... - @overload - def __rsub__( - self: Series[Never], other: complex | _ListLike | Series + other: complex | datetime | np.datetime64 | _ListLike | Series, ) -> Series: ... @overload def __rsub__(self, other: Series[Never]) -> Series: ... @@ -2779,17 +2775,13 @@ class Series(IndexOpsMixin[S1], NDFrame): ), ) -> Series[complex]: ... @overload - def rsub( - self: Series[Never], - other: datetime | np.datetime64 | np_ndarray_dt | TimestampSeries, - level: Level | None = None, - fill_value: float | None = None, - axis: int = 0, + def __rsub__( + self: Series[Timestamp], other: datetime | np.datetime64 | np_ndarray_dt ) -> TimedeltaSeries: ... @overload def rsub( self: Series[Never], - other: complex | _ListLike | Series, + other: complex | datetime | np.datetime64 | _ListLike | Series, level: Level | None = None, fill_value: float | None = None, axis: int = 0, diff --git a/tests/series/arithmetic/str/test_add.py b/tests/series/arithmetic/str/test_add.py index 2eaffd59..fbcc7536 100644 --- a/tests/series/arithmetic/str/test_add.py +++ b/tests/series/arithmetic/str/test_add.py @@ -18,7 +18,7 @@ def test_add_py_scalar() -> None: - """Testpd.Series[str]+ Python native 'scalar's""" + """Test pd.Series[str] + Python native 'scalar's""" i = 4 r0 = "right" @@ -40,7 +40,7 @@ def test_add_py_scalar() -> None: def test_add_py_sequence() -> None: - """Testpd.Series[str]+ Python native sequence""" + """Test pd.Series[str] + Python native sequence""" i = [3, 5, 8] r0 = ["a", "bc", "def"] r1 = tuple(r0) @@ -67,7 +67,7 @@ def test_add_py_sequence() -> None: def test_add_numpy_array() -> None: - """Testpd.Series[str]+ numpy array""" + """Test pd.Series[str] + numpy array""" i = np.array([3, 5, 8], np.int64) r0 = np.array(["a", "bc", "def"], np.str_) @@ -101,7 +101,7 @@ def test_add_numpy_array() -> None: def test_add_pd_series() -> None: - """Testpd.Series[str]+ pandas series""" + """Test pd.Series[str] + pandas series""" i = pd.Series([3, 5, 8]) r0 = pd.Series(["a", "bc", "def"]) diff --git a/tests/series/arithmetic/test_add.py b/tests/series/arithmetic/test_add.py index e4d68c94..c663cc47 100644 --- a/tests/series/arithmetic/test_add.py +++ b/tests/series/arithmetic/test_add.py @@ -5,122 +5,127 @@ from tests import check -left = pd.DataFrame({"a": [1, 2, 3]})["a"] # left operand +left_i = pd.DataFrame({"a": [1, 2, 3]})["a"] # left operand -def test_add_py_scalar() -> None: - """Test pd.Series[Any] + Python native scalars""" +def test_add_i_py_scalar() -> None: + """Test pd.Series[Any] (int) + Python native scalars""" b, i, f, c = True, 1, 1.0, 1j - check(assert_type(left + b, pd.Series), pd.Series) - 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(left_i + b, pd.Series), pd.Series) + check(assert_type(left_i + i, pd.Series), pd.Series) + check(assert_type(left_i + f, pd.Series), pd.Series) + check(assert_type(left_i + c, pd.Series), pd.Series) - check(assert_type(b + left, 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(b + left_i, pd.Series), pd.Series) + check(assert_type(i + left_i, pd.Series), pd.Series) + check(assert_type(f + left_i, pd.Series), pd.Series) + check(assert_type(c + left_i, pd.Series), pd.Series) - check(assert_type(left.add(b), 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_i.add(b), pd.Series), pd.Series) + check(assert_type(left_i.add(i), pd.Series), pd.Series) + check(assert_type(left_i.add(f), pd.Series), pd.Series) + check(assert_type(left_i.add(c), pd.Series), pd.Series) - check(assert_type(left.radd(b), 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) + check(assert_type(left_i.radd(b), pd.Series), pd.Series) + check(assert_type(left_i.radd(i), pd.Series), pd.Series) + check(assert_type(left_i.radd(f), pd.Series), pd.Series) + check(assert_type(left_i.radd(c), pd.Series), pd.Series) -def test_add_py_sequence() -> None: - """Test pd.Series[Any] + Python native sequence""" +def test_add_i_py_sequence() -> None: + """Test pd.Series[Any] (int) + Python native sequence""" b, i, f, c = [True, False, True], [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] - check(assert_type(left + b, pd.Series), pd.Series) - 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(left_i + b, pd.Series), pd.Series) + check(assert_type(left_i + i, pd.Series), pd.Series) + check(assert_type(left_i + f, pd.Series), pd.Series) + check(assert_type(left_i + c, pd.Series), pd.Series) - check(assert_type(b + left, 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(b + left_i, pd.Series), pd.Series) + check(assert_type(i + left_i, pd.Series), pd.Series) + check(assert_type(f + left_i, pd.Series), pd.Series) + check(assert_type(c + left_i, pd.Series), pd.Series) - check(assert_type(left.add(b), 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_i.add(b), pd.Series), pd.Series) + check(assert_type(left_i.add(i), pd.Series), pd.Series) + check(assert_type(left_i.add(f), pd.Series), pd.Series) + check(assert_type(left_i.add(c), pd.Series), pd.Series) - check(assert_type(left.radd(b), 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) + check(assert_type(left_i.radd(b), pd.Series), pd.Series) + check(assert_type(left_i.radd(i), pd.Series), pd.Series) + check(assert_type(left_i.radd(f), pd.Series), pd.Series) + check(assert_type(left_i.radd(c), pd.Series), pd.Series) -def test_add_numpy_array() -> None: - """Test pd.Series[Any] + numpy array""" +def test_add_i_numpy_array() -> None: + """Test pd.Series[Any] (int) + numpy array""" b = np.array([True, False, True], np.bool_) 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 + b, pd.Series), pd.Series) - 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(left_i + b, pd.Series), pd.Series) + check(assert_type(left_i + i, pd.Series), pd.Series) + check(assert_type(left_i + f, pd.Series), pd.Series) + check(assert_type(left_i + c, pd.Series), pd.Series) # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__radd__` cannot override. At runtime, they return # `Series`s. # `mypy` thinks the return types are `Any`, which is a bug. check( - assert_type(b + left, "npt.NDArray[np.bool_]"), pd.Series # type: ignore[assert-type] + assert_type(b + left_i, "npt.NDArray[np.bool_]"), pd.Series # type: ignore[assert-type] ) check( - assert_type(i + left, "npt.NDArray[np.int64]"), pd.Series # type: ignore[assert-type] + assert_type(i + left_i, "npt.NDArray[np.int64]"), pd.Series # type: ignore[assert-type] ) check( - assert_type(f + left, "npt.NDArray[np.float64]"), pd.Series # type: ignore[assert-type] + assert_type(f + left_i, "npt.NDArray[np.float64]"), pd.Series # type: ignore[assert-type] ) check( - assert_type(c + left, "npt.NDArray[np.complex128]"), pd.Series # type: ignore[assert-type] + assert_type(c + left_i, "npt.NDArray[np.complex128]"), pd.Series # type: ignore[assert-type] ) - check(assert_type(left.add(b), 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_i.add(b), pd.Series), pd.Series) + check(assert_type(left_i.add(i), pd.Series), pd.Series) + check(assert_type(left_i.add(f), pd.Series), pd.Series) + check(assert_type(left_i.add(c), pd.Series), pd.Series) - check(assert_type(left.radd(b), 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) + check(assert_type(left_i.radd(b), pd.Series), pd.Series) + check(assert_type(left_i.radd(i), pd.Series), pd.Series) + check(assert_type(left_i.radd(f), pd.Series), pd.Series) + check(assert_type(left_i.radd(c), pd.Series), pd.Series) -def test_add_pd_series() -> None: - """Test pd.Series[Any] + pandas series""" +def test_add_i_pd_series() -> None: + """Test pd.Series[Any] (int) + pandas series""" + a = pd.DataFrame({"a": [1, 2, 3]})["a"] b = pd.Series([True, False, True]) 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 + b, pd.Series), pd.Series) - 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(b + left, 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(b), 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(b), 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) + check(assert_type(left_i + a, pd.Series), pd.Series) + check(assert_type(left_i + b, pd.Series), pd.Series) + check(assert_type(left_i + i, pd.Series), pd.Series) + check(assert_type(left_i + f, pd.Series), pd.Series) + check(assert_type(left_i + c, pd.Series), pd.Series) + + check(assert_type(a + left_i, pd.Series), pd.Series) + check(assert_type(b + left_i, pd.Series), pd.Series) + check(assert_type(i + left_i, pd.Series), pd.Series) + check(assert_type(f + left_i, pd.Series), pd.Series) + check(assert_type(c + left_i, pd.Series), pd.Series) + + check(assert_type(left_i.add(a), pd.Series), pd.Series) + check(assert_type(left_i.add(b), pd.Series), pd.Series) + check(assert_type(left_i.add(i), pd.Series), pd.Series) + check(assert_type(left_i.add(f), pd.Series), pd.Series) + check(assert_type(left_i.add(c), pd.Series), pd.Series) + + check(assert_type(left_i.radd(a), pd.Series), pd.Series) + check(assert_type(left_i.radd(b), pd.Series), pd.Series) + check(assert_type(left_i.radd(i), pd.Series), pd.Series) + check(assert_type(left_i.radd(f), pd.Series), pd.Series) + check(assert_type(left_i.radd(c), pd.Series), pd.Series) diff --git a/tests/series/arithmetic/test_mul.py b/tests/series/arithmetic/test_mul.py index ec7ed5f4..335a6014 100644 --- a/tests/series/arithmetic/test_mul.py +++ b/tests/series/arithmetic/test_mul.py @@ -5,122 +5,127 @@ from tests import check -left = pd.DataFrame({"a": [1, 2, 3]})["a"] # left operand +left_i = pd.DataFrame({"a": [1, 2, 3]})["a"] # left operand def test_mul_py_scalar() -> None: - """Test pd.Series[Any] * Python native scalars""" + """Test pd.Series[Any] (int) * Python native scalars""" b, i, f, c = True, 1, 1.0, 1j - check(assert_type(left * b, pd.Series), pd.Series) - 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(left_i * b, pd.Series), pd.Series) + check(assert_type(left_i * i, pd.Series), pd.Series) + check(assert_type(left_i * f, pd.Series), pd.Series) + check(assert_type(left_i * c, pd.Series), pd.Series) - check(assert_type(b * left, 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(b * left_i, pd.Series), pd.Series) + check(assert_type(i * left_i, pd.Series), pd.Series) + check(assert_type(f * left_i, pd.Series), pd.Series) + check(assert_type(c * left_i, pd.Series), pd.Series) - check(assert_type(left.mul(b), pd.Series), pd.Series) - check(assert_type(left.mul(i), pd.Series), pd.Series) - check(assert_type(left.mul(f), pd.Series), pd.Series) - check(assert_type(left.mul(c), pd.Series), pd.Series) + check(assert_type(left_i.mul(b), pd.Series), pd.Series) + check(assert_type(left_i.mul(i), pd.Series), pd.Series) + check(assert_type(left_i.mul(f), pd.Series), pd.Series) + check(assert_type(left_i.mul(c), pd.Series), pd.Series) - check(assert_type(left.rmul(b), pd.Series), pd.Series) - check(assert_type(left.rmul(i), pd.Series), pd.Series) - check(assert_type(left.rmul(f), pd.Series), pd.Series) - check(assert_type(left.rmul(c), pd.Series), pd.Series) + check(assert_type(left_i.rmul(b), pd.Series), pd.Series) + check(assert_type(left_i.rmul(i), pd.Series), pd.Series) + check(assert_type(left_i.rmul(f), pd.Series), pd.Series) + check(assert_type(left_i.rmul(c), pd.Series), pd.Series) def test_mul_py_sequence() -> None: - """Test pd.Series[Any] * Python native sequence""" + """Test pd.Series[Any] (int) * Python native sequence""" b, i, f, c = [True, False, True], [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] - check(assert_type(left * b, pd.Series), pd.Series) - 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(left_i * b, pd.Series), pd.Series) + check(assert_type(left_i * i, pd.Series), pd.Series) + check(assert_type(left_i * f, pd.Series), pd.Series) + check(assert_type(left_i * c, pd.Series), pd.Series) - check(assert_type(b * left, 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(b * left_i, pd.Series), pd.Series) + check(assert_type(i * left_i, pd.Series), pd.Series) + check(assert_type(f * left_i, pd.Series), pd.Series) + check(assert_type(c * left_i, pd.Series), pd.Series) - check(assert_type(left.mul(b), pd.Series), pd.Series) - check(assert_type(left.mul(i), pd.Series), pd.Series) - check(assert_type(left.mul(f), pd.Series), pd.Series) - check(assert_type(left.mul(c), pd.Series), pd.Series) + check(assert_type(left_i.mul(b), pd.Series), pd.Series) + check(assert_type(left_i.mul(i), pd.Series), pd.Series) + check(assert_type(left_i.mul(f), pd.Series), pd.Series) + check(assert_type(left_i.mul(c), pd.Series), pd.Series) - check(assert_type(left.rmul(b), pd.Series), pd.Series) - check(assert_type(left.rmul(i), pd.Series), pd.Series) - check(assert_type(left.rmul(f), pd.Series), pd.Series) - check(assert_type(left.rmul(c), pd.Series), pd.Series) + check(assert_type(left_i.rmul(b), pd.Series), pd.Series) + check(assert_type(left_i.rmul(i), pd.Series), pd.Series) + check(assert_type(left_i.rmul(f), pd.Series), pd.Series) + check(assert_type(left_i.rmul(c), pd.Series), pd.Series) def test_mul_numpy_array() -> None: - """Test pd.Series[Any] * numpy array""" + """Test pd.Series[Any] (int) * numpy array""" b = np.array([True, False, True], np.bool_) 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 * b, pd.Series), pd.Series) - 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(left_i * b, pd.Series), pd.Series) + check(assert_type(left_i * i, pd.Series), pd.Series) + check(assert_type(left_i * f, pd.Series), pd.Series) + check(assert_type(left_i * c, pd.Series), pd.Series) # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rmul__` cannot override. At runtime, they return # `Series`s. # `mypy` thinks the return types are `Any`, which is a bug. check( - assert_type(b * left, "npt.NDArray[np.bool_]"), pd.Series # type: ignore[assert-type] + assert_type(b * left_i, "npt.NDArray[np.bool_]"), pd.Series # type: ignore[assert-type] ) check( - assert_type(i * left, "npt.NDArray[np.int64]"), pd.Series # type: ignore[assert-type] + assert_type(i * left_i, "npt.NDArray[np.int64]"), pd.Series # type: ignore[assert-type] ) check( - assert_type(f * left, "npt.NDArray[np.float64]"), pd.Series # type: ignore[assert-type] + assert_type(f * left_i, "npt.NDArray[np.float64]"), pd.Series # type: ignore[assert-type] ) check( - assert_type(c * left, "npt.NDArray[np.complex128]"), pd.Series # type: ignore[assert-type] + assert_type(c * left_i, "npt.NDArray[np.complex128]"), pd.Series # type: ignore[assert-type] ) - check(assert_type(left.mul(b), pd.Series), pd.Series) - check(assert_type(left.mul(i), pd.Series), pd.Series) - check(assert_type(left.mul(f), pd.Series), pd.Series) - check(assert_type(left.mul(c), pd.Series), pd.Series) + check(assert_type(left_i.mul(b), pd.Series), pd.Series) + check(assert_type(left_i.mul(i), pd.Series), pd.Series) + check(assert_type(left_i.mul(f), pd.Series), pd.Series) + check(assert_type(left_i.mul(c), pd.Series), pd.Series) - check(assert_type(left.rmul(b), pd.Series), pd.Series) - check(assert_type(left.rmul(i), pd.Series), pd.Series) - check(assert_type(left.rmul(f), pd.Series), pd.Series) - check(assert_type(left.rmul(c), pd.Series), pd.Series) + check(assert_type(left_i.rmul(b), pd.Series), pd.Series) + check(assert_type(left_i.rmul(i), pd.Series), pd.Series) + check(assert_type(left_i.rmul(f), pd.Series), pd.Series) + check(assert_type(left_i.rmul(c), pd.Series), pd.Series) def test_mul_pd_series() -> None: - """Test pd.Series[Any] * pandas series""" + """Test pd.Series[Any] (int) * pandas series""" + a = pd.DataFrame({"a": [1, 2, 3]})["a"] b = pd.Series([True, False, True]) 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 * b, pd.Series), pd.Series) - 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(b * left, 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.mul(b), pd.Series), pd.Series) - check(assert_type(left.mul(i), pd.Series), pd.Series) - check(assert_type(left.mul(f), pd.Series), pd.Series) - check(assert_type(left.mul(c), pd.Series), pd.Series) - - check(assert_type(left.rmul(b), pd.Series), pd.Series) - check(assert_type(left.rmul(i), pd.Series), pd.Series) - check(assert_type(left.rmul(f), pd.Series), pd.Series) - check(assert_type(left.rmul(c), pd.Series), pd.Series) + check(assert_type(left_i * a, pd.Series), pd.Series) + check(assert_type(left_i * b, pd.Series), pd.Series) + check(assert_type(left_i * i, pd.Series), pd.Series) + check(assert_type(left_i * f, pd.Series), pd.Series) + check(assert_type(left_i * c, pd.Series), pd.Series) + + check(assert_type(a * left_i, pd.Series), pd.Series) + check(assert_type(b * left_i, pd.Series), pd.Series) + check(assert_type(i * left_i, pd.Series), pd.Series) + check(assert_type(f * left_i, pd.Series), pd.Series) + check(assert_type(c * left_i, pd.Series), pd.Series) + + check(assert_type(left_i.mul(a), pd.Series), pd.Series) + check(assert_type(left_i.mul(b), pd.Series), pd.Series) + check(assert_type(left_i.mul(i), pd.Series), pd.Series) + check(assert_type(left_i.mul(f), pd.Series), pd.Series) + check(assert_type(left_i.mul(c), pd.Series), pd.Series) + + check(assert_type(left_i.rmul(a), pd.Series), pd.Series) + check(assert_type(left_i.rmul(b), pd.Series), pd.Series) + check(assert_type(left_i.rmul(i), pd.Series), pd.Series) + check(assert_type(left_i.rmul(f), pd.Series), pd.Series) + check(assert_type(left_i.rmul(c), pd.Series), pd.Series) diff --git a/tests/series/arithmetic/test_sub.py b/tests/series/arithmetic/test_sub.py index 636aa242..f6c489e4 100644 --- a/tests/series/arithmetic/test_sub.py +++ b/tests/series/arithmetic/test_sub.py @@ -12,16 +12,24 @@ import pandas as pd from typing_extensions import assert_type -from tests import check +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) if TYPE_CHECKING: from pandas.core.series import TimedeltaSeries # noqa: F401 -left_i = pd.DataFrame({"a": [1, 2, 3]})["a"] # left operand +anchor = datetime(2025, 8, 18) + +# left operands +left_i = pd.DataFrame({"a": [1, 2, 3]})["a"] +left_ts = pd.DataFrame({"a": [anchor + timedelta(hours=h + 1) for h in range(3)]})["a"] +left_td = pd.DataFrame({"a": [timedelta(hours=h, minutes=1) for h in range(3)]})["a"] -def test_sub_py_scalar() -> None: - """Test pd.Series[Any] - Python native scalars""" +def test_sub_i_py_scalar() -> None: + """Test pd.Series[Any] (int) - Python native scalars""" b, i, f, c = True, 1, 1.0, 1j check(assert_type(left_i - b, pd.Series), pd.Series) @@ -45,8 +53,8 @@ def test_sub_py_scalar() -> None: check(assert_type(left_i.rsub(c), pd.Series), pd.Series) -def test_sub_py_sequence() -> None: - """Test pd.Series[Any] - Python native sequence""" +def test_sub_i_py_sequence() -> None: + """Test pd.Series[Any] (int) - Python native sequence""" b, i, f, c = [True, False, True], [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] check(assert_type(left_i - b, pd.Series), pd.Series) @@ -70,8 +78,8 @@ def test_sub_py_sequence() -> None: check(assert_type(left_i.rsub(c), pd.Series), pd.Series) -def test_sub_numpy_array() -> None: - """Test pd.Series[Any] - numpy array""" +def test_sub_i_numpy_array() -> None: + """Test pd.Series[Any] (int) - numpy array""" b = np.array([True, False, True], np.bool_) i = np.array([2, 3, 5], np.int64) f = np.array([1.0, 2.0, 3.0], np.float64) @@ -108,85 +116,112 @@ def test_sub_numpy_array() -> None: check(assert_type(left_i.rsub(c), pd.Series), pd.Series) -def test_sub_pd_series() -> None: - """Test pd.Series[Any] - pandas series""" +def test_sub_i_pd_series() -> None: + """Test pd.Series[Any] (int) - pandas series""" + a = pd.DataFrame({"a": [1, 2, 3]})["a"] b = pd.Series([True, False, True]) 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 - a, pd.Series), pd.Series) check(assert_type(left_i - b, pd.Series), pd.Series) check(assert_type(left_i - i, pd.Series), pd.Series) check(assert_type(left_i - f, pd.Series), pd.Series) check(assert_type(left_i - c, pd.Series), pd.Series) + check(assert_type(a - left_i, pd.Series), pd.Series) check(assert_type(b - left_i, pd.Series), pd.Series) check(assert_type(i - left_i, pd.Series), pd.Series) check(assert_type(f - left_i, pd.Series), pd.Series) check(assert_type(c - left_i, pd.Series), pd.Series) + check(assert_type(left_i.sub(a), pd.Series), pd.Series) check(assert_type(left_i.sub(b), pd.Series), pd.Series) check(assert_type(left_i.sub(i), pd.Series), pd.Series) check(assert_type(left_i.sub(f), pd.Series), pd.Series) check(assert_type(left_i.sub(c), pd.Series), pd.Series) + check(assert_type(left_i.rsub(a), pd.Series), pd.Series) check(assert_type(left_i.rsub(b), pd.Series), pd.Series) check(assert_type(left_i.rsub(i), pd.Series), pd.Series) check(assert_type(left_i.rsub(f), pd.Series), pd.Series) check(assert_type(left_i.rsub(c), pd.Series), pd.Series) -anchor = datetime(2025, 8, 18) -left_ts = pd.DataFrame({"a": [anchor + timedelta(hours=h + 1) for h in range(3)]})["a"] - - -def test_sub_py_datetime() -> None: - """Test pd.Series[Any] - Python native datetime""" +def test_sub_ts_py_datetime() -> None: + """Test pd.Series[Any] (Timestamp | Timedelta) - Python native datetime""" s = anchor check(assert_type(left_ts - s, "TimedeltaSeries"), pd.Series, pd.Timedelta) - check(assert_type(s - left_ts, "TimedeltaSeries"), pd.Series, pd.Timedelta) + check(assert_type(s - left_ts, pd.Series), pd.Series, pd.Timedelta) + check(assert_type(s - left_td, pd.Series), pd.Series, pd.Timestamp) check(assert_type(left_ts.sub(s), "TimedeltaSeries"), pd.Series, pd.Timedelta) - check(assert_type(left_ts.rsub(s), "TimedeltaSeries"), pd.Series, pd.Timedelta) + check(assert_type(left_ts.rsub(s), pd.Series), pd.Series, pd.Timedelta) + check(assert_type(left_td.rsub(s), pd.Series), pd.Series, pd.Timestamp) -def test_sub_numpy_datetime() -> None: - """Test pd.Series[Any] - numpy datetime(s)""" +def test_sub_ts_numpy_datetime() -> None: + """Test pd.Series[Any] (Timestamp | Timedelta) - numpy datetime(s)""" s = np.datetime64(anchor) a = np.array([s + np.timedelta64(m, "m") for m in range(3)], np.datetime64) check(assert_type(left_ts - s, "TimedeltaSeries"), pd.Series, pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + _0 = left_td - s check(assert_type(left_ts - a, "TimedeltaSeries"), pd.Series, pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + _1 = left_td - a - check(assert_type(s - left_ts, "TimedeltaSeries"), pd.Series, pd.Timedelta) + check(assert_type(s - left_ts, pd.Series), pd.Series, pd.Timedelta) + check(assert_type(s - left_td, pd.Series), pd.Series, pd.Timestamp) # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rsub__` cannot override. At runtime, they return # `Series`s. check(assert_type(a - left_ts, "npt.NDArray[np.datetime64]"), pd.Series, pd.Timedelta) # type: ignore[assert-type] + check(assert_type(a - left_td, "npt.NDArray[np.datetime64]"), pd.Series, pd.Timestamp) # type: ignore[assert-type] check(assert_type(left_ts.sub(s), "TimedeltaSeries"), pd.Series, pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + left_td.sub(s) check(assert_type(left_ts.sub(a), "TimedeltaSeries"), pd.Series, pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + left_td.sub(a) - check(assert_type(left_ts.rsub(s), "TimedeltaSeries"), pd.Series, pd.Timedelta) - check(assert_type(left_ts.rsub(a), "TimedeltaSeries"), pd.Series, pd.Timedelta) + check(assert_type(left_ts.rsub(s), pd.Series), pd.Series, pd.Timedelta) + check(assert_type(left_td.rsub(s), pd.Series), pd.Series, pd.Timestamp) + check(assert_type(left_ts.rsub(a), pd.Series), pd.Series, pd.Timedelta) + check(assert_type(left_td.rsub(a), pd.Series), pd.Series, pd.Timestamp) -def test_sub_pd_datetime() -> None: - """Test pd.Series[Any] - Pandas datetime(s)""" +def test_sub_ts_pd_datetime() -> None: + """Test pd.Series[Any] (Timestamp | Timedelta) - Pandas datetime(s)""" s = pd.Timestamp(anchor) a = pd.Series([s + pd.Timedelta(minutes=m) for m in range(3)]) check(assert_type(left_ts - s, "TimedeltaSeries"), pd.Series, pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + _0 = left_td - s check(assert_type(left_ts - a, "TimedeltaSeries"), pd.Series, pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + _1 = left_ts - a - check(assert_type(s - left_ts, "TimedeltaSeries"), pd.Series, pd.Timedelta) - check(assert_type(a - left_ts, "TimedeltaSeries"), pd.Series, pd.Timedelta) + check(assert_type(s - left_ts, pd.Series), pd.Series, pd.Timedelta) + check(assert_type(s - left_td, pd.Series), pd.Series, pd.Timestamp) + check(assert_type(a - left_ts, pd.Series), pd.Series, pd.Timedelta) + check(assert_type(a - left_td, pd.Series), pd.Series, pd.Timestamp) check(assert_type(left_ts.sub(s), "TimedeltaSeries"), pd.Series, pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + left_td.sub(s) check(assert_type(left_ts.sub(a), "TimedeltaSeries"), pd.Series, pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + left_td.sub(a) - check(assert_type(left_ts.rsub(s), "TimedeltaSeries"), pd.Series, pd.Timedelta) - check(assert_type(left_ts.rsub(a), "TimedeltaSeries"), pd.Series, pd.Timedelta) + check(assert_type(left_ts.rsub(s), pd.Series), pd.Series, pd.Timedelta) + check(assert_type(left_td.rsub(s), pd.Series), pd.Series, pd.Timestamp) + check(assert_type(left_ts.rsub(a), pd.Series), pd.Series, pd.Timedelta) + check(assert_type(left_td.rsub(a), pd.Series), pd.Series, pd.Timestamp) diff --git a/tests/series/arithmetic/test_truediv.py b/tests/series/arithmetic/test_truediv.py index 155a0c0e..69d408b3 100644 --- a/tests/series/arithmetic/test_truediv.py +++ b/tests/series/arithmetic/test_truediv.py @@ -10,165 +10,172 @@ check, ) -left = pd.DataFrame({"a": [1, 2, 3]})["a"] # left operand +left_i = pd.DataFrame({"a": [1, 2, 3]})["a"] # left operand def test_truediv_py_scalar() -> None: - """Test pd.Series[Any] / Python native scalars""" + """Test pd.Series[Any] (int) / Python native scalars""" b, i, f, c = True, 1, 1.0, 1j - check(assert_type(left / b, pd.Series), pd.Series) - 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(left_i / b, pd.Series), pd.Series) + check(assert_type(left_i / i, pd.Series), pd.Series) + check(assert_type(left_i / f, pd.Series), pd.Series) + check(assert_type(left_i / c, pd.Series), pd.Series) - check(assert_type(b / left, 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(b / left_i, pd.Series), pd.Series) + check(assert_type(i / left_i, pd.Series), pd.Series) + check(assert_type(f / left_i, pd.Series), pd.Series) + check(assert_type(c / left_i, pd.Series), pd.Series) - check(assert_type(left.truediv(b), pd.Series), pd.Series) - check(assert_type(left.truediv(i), pd.Series), pd.Series) - check(assert_type(left.truediv(f), pd.Series), pd.Series) - check(assert_type(left.truediv(c), pd.Series), pd.Series) + check(assert_type(left_i.truediv(b), pd.Series), pd.Series) + check(assert_type(left_i.truediv(i), pd.Series), pd.Series) + check(assert_type(left_i.truediv(f), pd.Series), pd.Series) + check(assert_type(left_i.truediv(c), pd.Series), pd.Series) - check(assert_type(left.div(b), pd.Series), pd.Series) - check(assert_type(left.div(i), pd.Series), pd.Series) - check(assert_type(left.div(f), pd.Series), pd.Series) - check(assert_type(left.div(c), pd.Series), pd.Series) + check(assert_type(left_i.div(b), pd.Series), pd.Series) + check(assert_type(left_i.div(i), pd.Series), pd.Series) + check(assert_type(left_i.div(f), pd.Series), pd.Series) + check(assert_type(left_i.div(c), pd.Series), pd.Series) - check(assert_type(left.rtruediv(b), pd.Series), pd.Series) - check(assert_type(left.rtruediv(i), pd.Series), pd.Series) - check(assert_type(left.rtruediv(f), pd.Series), pd.Series) - check(assert_type(left.rtruediv(c), pd.Series), pd.Series) + check(assert_type(left_i.rtruediv(b), pd.Series), pd.Series) + check(assert_type(left_i.rtruediv(i), pd.Series), pd.Series) + check(assert_type(left_i.rtruediv(f), pd.Series), pd.Series) + check(assert_type(left_i.rtruediv(c), pd.Series), pd.Series) - check(assert_type(left.rdiv(b), pd.Series), pd.Series) - check(assert_type(left.rdiv(i), pd.Series), pd.Series) - check(assert_type(left.rdiv(f), pd.Series), pd.Series) - check(assert_type(left.rdiv(c), pd.Series), pd.Series) + check(assert_type(left_i.rdiv(b), pd.Series), pd.Series) + check(assert_type(left_i.rdiv(i), pd.Series), pd.Series) + check(assert_type(left_i.rdiv(f), pd.Series), pd.Series) + check(assert_type(left_i.rdiv(c), pd.Series), pd.Series) def test_truediv_py_sequence() -> None: - """Test pd.Series[Any] / Python native sequence""" + """Test pd.Series[Any] (int) / Python native sequence""" b, i, f, c = [True, False, True], [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] - check(assert_type(left / b, pd.Series), pd.Series) - 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(left_i / b, pd.Series), pd.Series) + check(assert_type(left_i / i, pd.Series), pd.Series) + check(assert_type(left_i / f, pd.Series), pd.Series) + check(assert_type(left_i / c, pd.Series), pd.Series) - check(assert_type(b / left, 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(b / left_i, pd.Series), pd.Series) + check(assert_type(i / left_i, pd.Series), pd.Series) + check(assert_type(f / left_i, pd.Series), pd.Series) + check(assert_type(c / left_i, pd.Series), pd.Series) - check(assert_type(left.truediv(b), pd.Series), pd.Series) - check(assert_type(left.truediv(i), pd.Series), pd.Series) - check(assert_type(left.truediv(f), pd.Series), pd.Series) - check(assert_type(left.truediv(c), pd.Series), pd.Series) + check(assert_type(left_i.truediv(b), pd.Series), pd.Series) + check(assert_type(left_i.truediv(i), pd.Series), pd.Series) + check(assert_type(left_i.truediv(f), pd.Series), pd.Series) + check(assert_type(left_i.truediv(c), pd.Series), pd.Series) - check(assert_type(left.div(b), pd.Series), pd.Series) - check(assert_type(left.div(i), pd.Series), pd.Series) - check(assert_type(left.div(f), pd.Series), pd.Series) - check(assert_type(left.div(c), pd.Series), pd.Series) + check(assert_type(left_i.div(b), pd.Series), pd.Series) + check(assert_type(left_i.div(i), pd.Series), pd.Series) + check(assert_type(left_i.div(f), pd.Series), pd.Series) + check(assert_type(left_i.div(c), pd.Series), pd.Series) - check(assert_type(left.rtruediv(b), pd.Series), pd.Series) - check(assert_type(left.rtruediv(i), pd.Series), pd.Series) - check(assert_type(left.rtruediv(f), pd.Series), pd.Series) - check(assert_type(left.rtruediv(c), pd.Series), pd.Series) + check(assert_type(left_i.rtruediv(b), pd.Series), pd.Series) + check(assert_type(left_i.rtruediv(i), pd.Series), pd.Series) + check(assert_type(left_i.rtruediv(f), pd.Series), pd.Series) + check(assert_type(left_i.rtruediv(c), pd.Series), pd.Series) - check(assert_type(left.rdiv(b), pd.Series), pd.Series) - check(assert_type(left.rdiv(i), pd.Series), pd.Series) - check(assert_type(left.rdiv(f), pd.Series), pd.Series) - check(assert_type(left.rdiv(c), pd.Series), pd.Series) + check(assert_type(left_i.rdiv(b), pd.Series), pd.Series) + check(assert_type(left_i.rdiv(i), pd.Series), pd.Series) + check(assert_type(left_i.rdiv(f), pd.Series), pd.Series) + check(assert_type(left_i.rdiv(c), pd.Series), pd.Series) def test_truediv_numpy_array() -> None: - """Test pd.Series[Any] / numpy array""" + """Test pd.Series[Any] (int) / numpy array""" b = np.array([True, False, True], np.bool_) 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 / b, pd.Series), pd.Series) - 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(left_i / b, pd.Series), pd.Series) + check(assert_type(left_i / i, pd.Series), pd.Series) + check(assert_type(left_i / f, pd.Series), pd.Series) + check(assert_type(left_i / c, pd.Series), pd.Series) # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rtruediv__` cannot override. At runtime, they return # `Series`s. # `mypy` thinks the return types are `Any`, which is a bug. check( - assert_type(b / left, "npt.NDArray[np.float64]"), pd.Series # type: ignore[assert-type] + assert_type(b / left_i, "npt.NDArray[np.float64]"), pd.Series # type: ignore[assert-type] ) check( - assert_type(i / left, "npt.NDArray[np.float64]"), pd.Series # type: ignore[assert-type] + assert_type(i / left_i, "npt.NDArray[np.float64]"), pd.Series # type: ignore[assert-type] ) check( - assert_type(f / left, "npt.NDArray[np.float64]"), pd.Series # type: ignore[assert-type] + assert_type(f / left_i, "npt.NDArray[np.float64]"), pd.Series # type: ignore[assert-type] ) check( - assert_type(c / left, "npt.NDArray[np.complex128]"), pd.Series # type: ignore[assert-type] + assert_type(c / left_i, "npt.NDArray[np.complex128]"), pd.Series # type: ignore[assert-type] ) - check(assert_type(left.truediv(b), pd.Series), pd.Series) - check(assert_type(left.truediv(i), pd.Series), pd.Series) - check(assert_type(left.truediv(f), pd.Series), pd.Series) - check(assert_type(left.truediv(c), pd.Series), pd.Series) + check(assert_type(left_i.truediv(b), pd.Series), pd.Series) + check(assert_type(left_i.truediv(i), pd.Series), pd.Series) + check(assert_type(left_i.truediv(f), pd.Series), pd.Series) + check(assert_type(left_i.truediv(c), pd.Series), pd.Series) - check(assert_type(left.div(b), pd.Series), pd.Series) - check(assert_type(left.div(i), pd.Series), pd.Series) - check(assert_type(left.div(f), pd.Series), pd.Series) - check(assert_type(left.div(c), pd.Series), pd.Series) + check(assert_type(left_i.div(b), pd.Series), pd.Series) + check(assert_type(left_i.div(i), pd.Series), pd.Series) + check(assert_type(left_i.div(f), pd.Series), pd.Series) + check(assert_type(left_i.div(c), pd.Series), pd.Series) - check(assert_type(left.rtruediv(b), pd.Series), pd.Series) - check(assert_type(left.rtruediv(i), pd.Series), pd.Series) - check(assert_type(left.rtruediv(f), pd.Series), pd.Series) - check(assert_type(left.rtruediv(c), pd.Series), pd.Series) + check(assert_type(left_i.rtruediv(b), pd.Series), pd.Series) + check(assert_type(left_i.rtruediv(i), pd.Series), pd.Series) + check(assert_type(left_i.rtruediv(f), pd.Series), pd.Series) + check(assert_type(left_i.rtruediv(c), pd.Series), pd.Series) - check(assert_type(left.rdiv(b), pd.Series), pd.Series) - check(assert_type(left.rdiv(i), pd.Series), pd.Series) - check(assert_type(left.rdiv(f), pd.Series), pd.Series) - check(assert_type(left.rdiv(c), pd.Series), pd.Series) + check(assert_type(left_i.rdiv(b), pd.Series), pd.Series) + check(assert_type(left_i.rdiv(i), pd.Series), pd.Series) + check(assert_type(left_i.rdiv(f), pd.Series), pd.Series) + check(assert_type(left_i.rdiv(c), pd.Series), pd.Series) def test_truediv_pd_series() -> None: - """Test pd.Series[Any] / pandas series""" + """Test pd.Series[Any] (int) / pandas series""" + a = pd.DataFrame({"a": [1, 2, 3]})["a"] b = pd.Series([True, False, True]) 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 / b, pd.Series), pd.Series) - 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(b / left, 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.truediv(b), pd.Series), pd.Series) - check(assert_type(left.truediv(i), pd.Series), pd.Series) - check(assert_type(left.truediv(f), pd.Series), pd.Series) - check(assert_type(left.truediv(c), pd.Series), pd.Series) - - check(assert_type(left.div(b), pd.Series), pd.Series) - check(assert_type(left.div(i), pd.Series), pd.Series) - check(assert_type(left.div(f), pd.Series), pd.Series) - check(assert_type(left.div(c), pd.Series), pd.Series) - - check(assert_type(left.rtruediv(b), pd.Series), pd.Series) - check(assert_type(left.rtruediv(i), pd.Series), pd.Series) - check(assert_type(left.rtruediv(f), pd.Series), pd.Series) - check(assert_type(left.rtruediv(c), pd.Series), pd.Series) - - check(assert_type(left.rdiv(b), pd.Series), pd.Series) - check(assert_type(left.rdiv(i), pd.Series), pd.Series) - check(assert_type(left.rdiv(f), pd.Series), pd.Series) - check(assert_type(left.rdiv(c), pd.Series), pd.Series) + check(assert_type(left_i / a, pd.Series), pd.Series) + check(assert_type(left_i / b, pd.Series), pd.Series) + check(assert_type(left_i / i, pd.Series), pd.Series) + check(assert_type(left_i / f, pd.Series), pd.Series) + check(assert_type(left_i / c, pd.Series), pd.Series) + + check(assert_type(a / left_i, pd.Series), pd.Series) + check(assert_type(b / left_i, pd.Series), pd.Series) + check(assert_type(i / left_i, pd.Series), pd.Series) + check(assert_type(f / left_i, pd.Series), pd.Series) + check(assert_type(c / left_i, pd.Series), pd.Series) + + check(assert_type(left_i.truediv(a), pd.Series), pd.Series) + check(assert_type(left_i.truediv(b), pd.Series), pd.Series) + check(assert_type(left_i.truediv(i), pd.Series), pd.Series) + check(assert_type(left_i.truediv(f), pd.Series), pd.Series) + check(assert_type(left_i.truediv(c), pd.Series), pd.Series) + + check(assert_type(left_i.div(a), pd.Series), pd.Series) + check(assert_type(left_i.div(b), pd.Series), pd.Series) + check(assert_type(left_i.div(i), pd.Series), pd.Series) + check(assert_type(left_i.div(f), pd.Series), pd.Series) + check(assert_type(left_i.div(c), pd.Series), pd.Series) + + check(assert_type(left_i.rtruediv(a), pd.Series), pd.Series) + check(assert_type(left_i.rtruediv(b), pd.Series), pd.Series) + check(assert_type(left_i.rtruediv(i), pd.Series), pd.Series) + check(assert_type(left_i.rtruediv(f), pd.Series), pd.Series) + check(assert_type(left_i.rtruediv(c), pd.Series), pd.Series) + + check(assert_type(left_i.rdiv(a), pd.Series), pd.Series) + check(assert_type(left_i.rdiv(b), pd.Series), pd.Series) + check(assert_type(left_i.rdiv(i), pd.Series), pd.Series) + check(assert_type(left_i.rdiv(f), pd.Series), pd.Series) + check(assert_type(left_i.rdiv(c), pd.Series), pd.Series) def test_truediv_paths(tmp_path: Path) -> None: diff --git a/tests/series/test_series.py b/tests/series/test_series.py index af90cde4..12326fd1 100644 --- a/tests/series/test_series.py +++ b/tests/series/test_series.py @@ -844,17 +844,20 @@ def test_types_element_wise_arithmetic() -> None: def test_types_scalar_arithmetic() -> None: s = pd.Series([0, 1, -10]) - check(assert_type(s + 1, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(s.add(1, fill_value=0), "pd.Series[int]"), pd.Series, np.integer) - res_sub: pd.Series = s - 1 - res_sub2: pd.Series = s.sub(1, fill_value=0) + check(assert_type(s.sub(1, fill_value=0), "pd.Series[int]"), pd.Series, np.integer) - res_mul: pd.Series = s * 2 - res_mul2: pd.Series = s.mul(2, fill_value=0) + check(assert_type(s.mul(1, fill_value=0), "pd.Series[int]"), pd.Series, np.integer) - res_div: pd.Series = s / 2 - res_div2: pd.Series = s.div(2, fill_value=0) + check( + assert_type(s.truediv(2, fill_value=0), "pd.Series[float]"), + pd.Series, + np.floating, + ) + check( + assert_type(s.div(2, fill_value=0), "pd.Series[float]"), pd.Series, np.floating + ) res_floordiv: pd.Series = s // 2 res_floordiv2: pd.Series = s.floordiv(2, fill_value=0) @@ -868,14 +871,6 @@ def test_types_scalar_arithmetic() -> None: res_pow3: pd.Series = s.pow(0.5) -def test_types_complex_arithmetic() -> None: - """Test adding complex number to pd.Series[float] GH 103.""" - c = 1 + 1j - s = pd.Series([1.0, 2.0, 3.0]) - x = s + c - y = s - c - - def test_types_groupby() -> None: s = pd.Series([4, 2, 1, 8], index=["a", "b", "a", "b"]) s.groupby(["a", "b", "a", "b"]) @@ -1594,16 +1589,8 @@ def test_series_loc_setitem() -> None: def test_series_min_max_sub_axis() -> None: df = pd.DataFrame({"x": [1, 2, 3, 4, 5], "y": [5, 4, 3, 2, 1]}) - s1 = df.min(axis=1) - s2 = df.max(axis=1) - sa = s1 + s2 - ss = s1 - s2 - sm = s1 * s2 - sd = s1 / s2 - 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) + check(assert_type(df.min(axis=1), pd.Series), pd.Series) + check(assert_type(df.max(axis=1), pd.Series), pd.Series) def test_series_index_isin() -> None: @@ -1654,12 +1641,6 @@ def test_reset_index() -> None: assert assert_type(s.reset_index(inplace=True, drop=True), None) is None -def test_series_add_str() -> None: - s = pd.Series(["abc", "def"]) - check(assert_type(s + "x", "pd.Series[str]"), pd.Series, str) - check(assert_type("x" + s, "pd.Series[str]"), pd.Series, str) - - def test_series_dtype() -> None: s = pd.Series(["abc", "def"], dtype=str) check(assert_type(s, "pd.Series[str]"), pd.Series, str) From 1fb597b0c273f06882eb97e36e66dc41486801cb Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Sat, 23 Aug 2025 10:41:51 +0200 Subject: [PATCH 2/7] fix(comment): https://github.com/pandas-dev/pandas-stubs/pull/1343#discussion_r2294233799 --- tests/series/arithmetic/test_sub.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/series/arithmetic/test_sub.py b/tests/series/arithmetic/test_sub.py index f6c489e4..0e76a012 100644 --- a/tests/series/arithmetic/test_sub.py +++ b/tests/series/arithmetic/test_sub.py @@ -207,7 +207,7 @@ def test_sub_ts_pd_datetime() -> None: _0 = left_td - s check(assert_type(left_ts - a, "TimedeltaSeries"), pd.Series, pd.Timedelta) if TYPE_CHECKING_INVALID_USAGE: - _1 = left_ts - a + _1 = left_td - a check(assert_type(s - left_ts, pd.Series), pd.Series, pd.Timedelta) check(assert_type(s - left_td, pd.Series), pd.Series, pd.Timestamp) From 961d692b6dac8b20856237d6a1cbfa7837d91f72 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Sun, 24 Aug 2025 11:57:20 +0200 Subject: [PATCH 3/7] chore(typing): update mypy and ty --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 046abe57..37236a87 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,12 +35,12 @@ types-pytz = ">= 2022.1.1" numpy = ">= 1.23.5" [tool.poetry.group.dev.dependencies] -mypy = "1.17.0" +mypy = "1.17.1" pandas = "2.3.1" pyarrow = ">=10.0.1" pytest = ">=7.1.2" pyright = ">=1.1.404" -ty = "^0.0.1a8" +ty = "^0.0.1a9" pyrefly = "^0.21.0" poethepoet = ">=0.16.5" loguru = ">=0.6.0" From e0b5b5903e9c694059d8a288cdcaa45b8b8379f1 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Sun, 24 Aug 2025 22:26:57 +0200 Subject: [PATCH 4/7] fix(comment): without str https://github.com/pandas-dev/pandas-stubs/pull/1343#issuecomment-3218217255 --- .pre-commit-config.yaml | 2 +- pandas-stubs/core/series.pyi | 45 ++++++---- tests/series/arithmetic/test_add.py | 4 +- tests/series/arithmetic/test_sub.py | 125 ++++++++++++++++------------ 4 files changed, 104 insertions(+), 72 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 02e86620..c04587ea 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: hooks: - id: isort - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.3 + rev: v0.12.10 hooks: - id: ruff-check args: [ diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 938360a4..a4f9bfd3 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -186,7 +186,6 @@ from pandas._typing import ( np_ndarray_anyint, np_ndarray_bool, np_ndarray_complex, - np_ndarray_dt, np_ndarray_float, np_ndarray_str, np_ndarray_td, @@ -264,6 +263,16 @@ class _LocIndexerSeries(_LocIndexer, Generic[S1]): _ListLike: TypeAlias = ( ArrayLike | dict[_str, np.ndarray] | Sequence[S1] | IndexOpsMixin[S1] ) +_NumListLike: TypeAlias = ( + ExtensionArray + | np_ndarray_bool + | np_ndarray_anyint + | np_ndarray_float + | np_ndarray_complex + | dict[_str, np.ndarray] + | Sequence[complex] + | IndexOpsMixin[complex] +) class Series(IndexOpsMixin[S1], NDFrame): # Define __index__ because mypy thinks Series follows protocol `SupportsIndex` https://github.com/pandas-dev/pandas-stubs/pull/1332#discussion_r2285648790 @@ -2475,12 +2484,11 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __rxor__(self, other: int | np_ndarray_anyint | Series[int]) -> Series[int]: ... @overload - def __sub__( - self: Series[Never], - other: datetime | np.datetime64 | np_ndarray_dt | TimestampSeries, - ) -> TimedeltaSeries: ... + def __sub__(self: Series[Never], other: TimestampSeries) -> Never: ... @overload - def __sub__(self: Series[Never], other: complex | _ListLike | Series) -> Series: ... + def __sub__( + self: Series[Never], other: complex | _NumListLike | Series + ) -> Series: ... @overload def __sub__(self, other: Series[Never]) -> Series: ... # type: ignore[overload-overlap] @overload @@ -2571,15 +2579,15 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def sub( self: Series[Never], - other: datetime | np.datetime64 | np_ndarray_dt | TimestampSeries, + other: TimestampSeries, level: Level | None = None, fill_value: float | None = None, axis: int = 0, - ) -> TimedeltaSeries: ... + ) -> Never: ... @overload def sub( self: Series[Never], - other: complex | _ListLike | Series, + other: complex | _NumListLike | Series, level: Level | None = None, fill_value: float | None = None, axis: int = 0, @@ -2705,9 +2713,10 @@ class Series(IndexOpsMixin[S1], NDFrame): axis: int = 0, ) -> TimedeltaSeries: ... @overload - def __rsub__( # type: ignore[overload-overlap] - self: Series[Never], - other: complex | datetime | np.datetime64 | _ListLike | Series, + def __rsub__(self: Series[Never], other: TimestampSeries) -> Never: ... # type: ignore[misc] + @overload + def __rsub__( + self: Series[Never], other: complex | _NumListLike | Series ) -> Series: ... @overload def __rsub__(self, other: Series[Never]) -> Series: ... @@ -2775,13 +2784,17 @@ class Series(IndexOpsMixin[S1], NDFrame): ), ) -> Series[complex]: ... @overload - def __rsub__( - self: Series[Timestamp], other: datetime | np.datetime64 | np_ndarray_dt - ) -> TimedeltaSeries: ... + def rsub( + self: Series[Never], + other: TimestampSeries, + level: Level | None = None, + fill_value: float | None = None, + axis: int = 0, + ) -> Never: ... @overload def rsub( self: Series[Never], - other: complex | datetime | np.datetime64 | _ListLike | Series, + other: complex | _NumListLike | Series, level: Level | None = None, fill_value: float | None = None, axis: int = 0, diff --git a/tests/series/arithmetic/test_add.py b/tests/series/arithmetic/test_add.py index c663cc47..d2d9630a 100644 --- a/tests/series/arithmetic/test_add.py +++ b/tests/series/arithmetic/test_add.py @@ -5,7 +5,9 @@ from tests import check -left_i = pd.DataFrame({"a": [1, 2, 3]})["a"] # left operand +# left operands +left_i = pd.DataFrame({"a": [1, 2, 3]})["a"] +left_str = pd.DataFrame({"a": ["1", "2", "3_"]})["a"] def test_add_i_py_scalar() -> None: diff --git a/tests/series/arithmetic/test_sub.py b/tests/series/arithmetic/test_sub.py index 0e76a012..a6df939f 100644 --- a/tests/series/arithmetic/test_sub.py +++ b/tests/series/arithmetic/test_sub.py @@ -2,24 +2,21 @@ datetime, timedelta, ) -from typing import ( - TYPE_CHECKING, - NoReturn, -) +from typing import NoReturn import numpy as np from numpy import typing as npt # noqa: F401 import pandas as pd -from typing_extensions import assert_type +from typing_extensions import ( + Never, + assert_type, +) from tests import ( TYPE_CHECKING_INVALID_USAGE, check, ) -if TYPE_CHECKING: - from pandas.core.series import TimedeltaSeries # noqa: F401 - anchor = datetime(2025, 8, 18) # left operands @@ -152,16 +149,28 @@ def test_sub_i_pd_series() -> None: def test_sub_ts_py_datetime() -> None: """Test pd.Series[Any] (Timestamp | Timedelta) - Python native datetime""" s = anchor + a = [s + timedelta(minutes=m) for m in range(3)] - check(assert_type(left_ts - s, "TimedeltaSeries"), pd.Series, pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + _0 = left_ts - s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _1 = left_ts - a # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _2 = left_td - s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _3 = left_td - a # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(s - left_ts, pd.Series), pd.Series, pd.Timedelta) - check(assert_type(s - left_td, pd.Series), pd.Series, pd.Timestamp) + _4 = s - left_ts # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _5 = a - left_ts # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _6 = s - left_td # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _7 = a - left_td # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(left_ts.sub(s), "TimedeltaSeries"), pd.Series, pd.Timedelta) + left_ts.sub(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_ts.sub(a) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_td.sub(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_td.sub(a) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - check(assert_type(left_ts.rsub(s), pd.Series), pd.Series, pd.Timedelta) - check(assert_type(left_td.rsub(s), pd.Series), pd.Series, pd.Timestamp) + left_ts.rsub(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_ts.rsub(a) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_td.rsub(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_td.rsub(a) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] def test_sub_ts_numpy_datetime() -> None: @@ -169,32 +178,28 @@ def test_sub_ts_numpy_datetime() -> None: s = np.datetime64(anchor) a = np.array([s + np.timedelta64(m, "m") for m in range(3)], np.datetime64) - check(assert_type(left_ts - s, "TimedeltaSeries"), pd.Series, pd.Timedelta) - if TYPE_CHECKING_INVALID_USAGE: - _0 = left_td - s - check(assert_type(left_ts - a, "TimedeltaSeries"), pd.Series, pd.Timedelta) if TYPE_CHECKING_INVALID_USAGE: - _1 = left_td - a + # `numpy` typing gives the corresponding `ndarray`s in the static type + # checking, where our `__rsub__` cannot override. + _0 = left_ts - s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + # _1 = left_ts - a + _2 = left_td - s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + # _3 = left_td - a - check(assert_type(s - left_ts, pd.Series), pd.Series, pd.Timedelta) - check(assert_type(s - left_td, pd.Series), pd.Series, pd.Timestamp) - # `numpy` typing gives the corresponding `ndarray`s in the static type - # checking, where our `__rsub__` cannot override. At runtime, they return - # `Series`s. - check(assert_type(a - left_ts, "npt.NDArray[np.datetime64]"), pd.Series, pd.Timedelta) # type: ignore[assert-type] - check(assert_type(a - left_td, "npt.NDArray[np.datetime64]"), pd.Series, pd.Timestamp) # type: ignore[assert-type] + _4 = s - left_ts # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + # _5 = a - left_ts + _6 = s - left_td # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + # _7 = a - left_td - check(assert_type(left_ts.sub(s), "TimedeltaSeries"), pd.Series, pd.Timedelta) - if TYPE_CHECKING_INVALID_USAGE: - left_td.sub(s) - check(assert_type(left_ts.sub(a), "TimedeltaSeries"), pd.Series, pd.Timedelta) - if TYPE_CHECKING_INVALID_USAGE: - left_td.sub(a) + left_ts.sub(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_ts.sub(a) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_td.sub(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_td.sub(a) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - check(assert_type(left_ts.rsub(s), pd.Series), pd.Series, pd.Timedelta) - check(assert_type(left_td.rsub(s), pd.Series), pd.Series, pd.Timestamp) - check(assert_type(left_ts.rsub(a), pd.Series), pd.Series, pd.Timedelta) - check(assert_type(left_td.rsub(a), pd.Series), pd.Series, pd.Timestamp) + left_ts.rsub(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_ts.rsub(a) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_td.rsub(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_td.rsub(a) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] def test_sub_ts_pd_datetime() -> None: @@ -202,26 +207,38 @@ def test_sub_ts_pd_datetime() -> None: s = pd.Timestamp(anchor) a = pd.Series([s + pd.Timedelta(minutes=m) for m in range(3)]) - check(assert_type(left_ts - s, "TimedeltaSeries"), pd.Series, pd.Timedelta) - if TYPE_CHECKING_INVALID_USAGE: - _0 = left_td - s - check(assert_type(left_ts - a, "TimedeltaSeries"), pd.Series, pd.Timedelta) if TYPE_CHECKING_INVALID_USAGE: - _1 = left_td - a + _0 = left_ts - s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + assert_type(left_ts - a, Never) + _2 = left_td - s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + assert_type(left_td - a, Never) - check(assert_type(s - left_ts, pd.Series), pd.Series, pd.Timedelta) - check(assert_type(s - left_td, pd.Series), pd.Series, pd.Timestamp) - check(assert_type(a - left_ts, pd.Series), pd.Series, pd.Timedelta) - check(assert_type(a - left_td, pd.Series), pd.Series, pd.Timestamp) + _4 = s - left_ts # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + assert_type(a - left_ts, Never) + _6 = s - left_td # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + assert_type(a - left_td, Never) + + left_ts.sub(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + assert_type(left_ts.sub(a), Never) + + +def test_sub_ts_pd_datetime_1() -> None: + """Test pd.Series[Any] (Timestamp | Timedelta) - Pandas datetime(s)""" + s = pd.Timestamp(anchor) + a = pd.Series([s + pd.Timedelta(minutes=m) for m in range(3)]) - check(assert_type(left_ts.sub(s), "TimedeltaSeries"), pd.Series, pd.Timedelta) - if TYPE_CHECKING_INVALID_USAGE: - left_td.sub(s) - check(assert_type(left_ts.sub(a), "TimedeltaSeries"), pd.Series, pd.Timedelta) if TYPE_CHECKING_INVALID_USAGE: - left_td.sub(a) + # When I merge this one to the previous one, mypy does not allow me to pass + left_ts.rsub(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + assert_type(left_ts.rsub(a), Never) - check(assert_type(left_ts.rsub(s), pd.Series), pd.Series, pd.Timedelta) - check(assert_type(left_td.rsub(s), pd.Series), pd.Series, pd.Timestamp) - check(assert_type(left_ts.rsub(a), pd.Series), pd.Series, pd.Timedelta) - check(assert_type(left_td.rsub(a), pd.Series), pd.Series, pd.Timestamp) + +def test_sub_ts_pd_datetime_2() -> None: + """Test pd.Series[Any] (Timestamp | Timedelta) - Pandas datetime(s)""" + s = pd.Timestamp(anchor) + a = pd.Series([s + pd.Timedelta(minutes=m) for m in range(3)]) + + if TYPE_CHECKING_INVALID_USAGE: + # When I merge this one to the previous one, mypy does not allow me to pass + left_td.rsub(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + assert_type(left_td.rsub(a), Never) From 9c972d3d61b70687c8ca9f6b88c2cdfd5216e678 Mon Sep 17 00:00:00 2001 From: Irv Lustig Date: Mon, 25 Aug 2025 10:47:00 -0400 Subject: [PATCH 5/7] handle str ops --- pandas-stubs/core/series.pyi | 21 +++++++++++++-------- tests/series/arithmetic/test_sub.py | 10 ++++++++++ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index a4f9bfd3..118fb149 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -260,7 +260,8 @@ class _LocIndexerSeries(_LocIndexer, Generic[S1]): value: S1 | ArrayLike | Series[S1] | None, ) -> None: ... -_ListLike: TypeAlias = ( +_ListLike: TypeAlias = ArrayLike | dict[_str, np.ndarray] | SequenceNotStr[S1] +_ListLikeS1: TypeAlias = ( ArrayLike | dict[_str, np.ndarray] | Sequence[S1] | IndexOpsMixin[S1] ) _NumListLike: TypeAlias = ( @@ -428,7 +429,9 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __new__( cls, - data: S1 | _ListLike[S1] | dict[HashableT1, S1] | KeysView[S1] | ValuesView[S1], + data: ( + S1 | _ListLikeS1[S1] | dict[HashableT1, S1] | KeysView[S1] | ValuesView[S1] + ), index: AxesData | None = ..., dtype: Dtype = ..., name: Hashable = ..., @@ -2060,7 +2063,9 @@ class Series(IndexOpsMixin[S1], NDFrame): self, other: S1 | _ListLike | Series[S1] | datetime | timedelta | date ) -> Series[_bool]: ... @overload - def __mul__(self: Series[Never], other: complex | _ListLike | Series) -> Series: ... + def __mul__( + self: Series[Never], other: complex | _NumListLike | Series + ) -> Series: ... @overload def __mul__(self, other: Series[Never]) -> Series: ... # type: ignore[overload-overlap] @overload @@ -2255,7 +2260,7 @@ class Series(IndexOpsMixin[S1], NDFrame): ) -> TimedeltaSeries: ... @overload def __rmul__( - self: Series[Never], other: complex | _ListLike | Series + self: Series[Never], other: complex | _NumListLike | Series ) -> Series: ... @overload def __rmul__(self, other: Series[Never]) -> Series: ... # type: ignore[overload-overlap] @@ -2892,8 +2897,8 @@ class Series(IndexOpsMixin[S1], NDFrame): axis: int = 0, ) -> Series[complex]: ... @overload - def __truediv__( - self: Series[Never], other: complex | _ListLike | Series + def __truediv__( # type:ignore[overload-overlap] + self: Series[Never], other: complex | _NumListLike | Series ) -> Series: ... @overload def __truediv__(self, other: Series[Never]) -> Series: ... @@ -3088,8 +3093,8 @@ class Series(IndexOpsMixin[S1], NDFrame): ) -> Series: ... div = truediv @overload - def __rtruediv__( - self: Series[Never], other: complex | _ListLike | Series + def __rtruediv__( # type:ignore[overload-overlap] + self: Series[Never], other: complex | _NumListLike | Series ) -> Series: ... @overload def __rtruediv__(self, other: Series[Never]) -> Series: ... diff --git a/tests/series/arithmetic/test_sub.py b/tests/series/arithmetic/test_sub.py index a6df939f..0d1a1833 100644 --- a/tests/series/arithmetic/test_sub.py +++ b/tests/series/arithmetic/test_sub.py @@ -242,3 +242,13 @@ def test_sub_ts_pd_datetime_2() -> None: # When I merge this one to the previous one, mypy does not allow me to pass left_td.rsub(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] assert_type(left_td.rsub(a), Never) + + +def test_str_sub() -> None: + if TYPE_CHECKING_INVALID_USAGE: + left_i - "abc" # type: ignore[operator] # pyright:ignore[reportOperatorIssue] + "abc" - left_i # type: ignore[operator] # pyright:ignore[reportOperatorIssue] + left_i * "abc" # type: ignore[operator] # pyright:ignore[reportOperatorIssue] + "abc" * left_i # type: ignore[operator] # pyright:ignore[reportOperatorIssue] + left_i / "abc" # type: ignore[operator] # pyright:ignore[reportOperatorIssue] + "abc" / left_i # type: ignore[operator] # pyright:ignore[reportOperatorIssue] From 41a0fb65903d26a93f7e3cb08a25de1148d9eac2 Mon Sep 17 00:00:00 2001 From: Irv Lustig Date: Tue, 26 Aug 2025 11:49:22 -0400 Subject: [PATCH 6/7] testing add ignores for mypy --- pandas-stubs/core/series.pyi | 34 ++++++++++++------------- tests/series/arithmetic/str/test_add.py | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 118fb149..fc98d8a7 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -1716,7 +1716,15 @@ class Series(IndexOpsMixin[S1], NDFrame): ) -> Series: ... @overload def add( - self, + self: Series[_str], + other: _str | Sequence[_str] | np_ndarray_str | Series[_str], + level: Level | None = None, + fill_value: float | None = None, + axis: int = 0, + ) -> Series[_str]: ... + @overload + def add( + self: Series[S1], other: Series[Never], level: Level | None = None, fill_value: float | None = None, @@ -1843,14 +1851,6 @@ class Series(IndexOpsMixin[S1], NDFrame): fill_value: float | None = None, axis: int = 0, ) -> Series[complex]: ... - @overload - def add( - self: Series[_str], - other: _str | Sequence[_str] | np_ndarray_str | Series[_str], - level: Level | None = None, - fill_value: float | None = None, - axis: int = 0, - ) -> Series[_str]: ... @overload # type: ignore[override] def __radd__(self: Series[Never], other: Scalar | _ListLike) -> Series: ... @overload @@ -1930,6 +1930,14 @@ class Series(IndexOpsMixin[S1], NDFrame): axis: int = 0, ) -> Series: ... @overload + def radd( + self: Series[_str], + other: _str | Sequence[_str] | np_ndarray_str | Series[_str], + level: Level | None = None, + fill_value: float | None = None, + axis: int = 0, + ) -> Series[_str]: ... + @overload def radd( self: Series[bool], other: _T_COMPLEX | Sequence[_T_COMPLEX] | Series[_T_COMPLEX], @@ -2033,14 +2041,6 @@ class Series(IndexOpsMixin[S1], NDFrame): fill_value: float | None = None, axis: int = 0, ) -> Series[complex]: ... - @overload - def radd( - self: Series[_str], - other: _str | Sequence[_str] | np_ndarray_str | Series[_str], - level: Level | None = None, - fill_value: float | None = None, - axis: int = 0, - ) -> Series[_str]: ... # ignore needed for mypy as we want different results based on the arguments @overload # type: ignore[override] def __and__( # pyright: ignore[reportOverlappingOverload] diff --git a/tests/series/arithmetic/str/test_add.py b/tests/series/arithmetic/str/test_add.py index fbcc7536..ff9a0332 100644 --- a/tests/series/arithmetic/str/test_add.py +++ b/tests/series/arithmetic/str/test_add.py @@ -31,7 +31,7 @@ def test_add_py_scalar() -> None: check(assert_type(r0 + left, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: - left.add(i) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.add(i) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.add(r0), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: From d3b8f164b2dc469146d43d49fd73eabc7ebe643a Mon Sep 17 00:00:00 2001 From: Irv Lustig Date: Tue, 26 Aug 2025 17:34:10 -0400 Subject: [PATCH 7/7] fix for nightly numpy --- pandas-stubs/core/series.pyi | 8 ++++++++ tests/series/arithmetic/str/test_add.py | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index fc98d8a7..aeeca9fe 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -1938,6 +1938,14 @@ class Series(IndexOpsMixin[S1], NDFrame): axis: int = 0, ) -> Series[_str]: ... @overload + def radd( + self: Series[S1], + other: Series[Never], + level: Level | None = None, + fill_value: float | None = None, + axis: int = 0, + ) -> Series: ... + @overload def radd( self: Series[bool], other: _T_COMPLEX | Sequence[_T_COMPLEX] | Series[_T_COMPLEX], diff --git a/tests/series/arithmetic/str/test_add.py b/tests/series/arithmetic/str/test_add.py index ff9a0332..a58fe663 100644 --- a/tests/series/arithmetic/str/test_add.py +++ b/tests/series/arithmetic/str/test_add.py @@ -31,11 +31,11 @@ def test_add_py_scalar() -> None: check(assert_type(r0 + left, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: - left.add(i) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.add(i) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.add(r0), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: - left.radd(i) # type: ignore[call-overload] # pyright: ignore[reportArgumentType] + left.radd(i) # type: ignore[call-overload] # pyright: ignore[reportArgumentType, reportCallIssue] check(assert_type(left.radd(r0), "pd.Series[str]"), pd.Series, str) @@ -61,7 +61,7 @@ def test_add_py_sequence() -> None: check(assert_type(left.add(r1), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: - left.radd(i) # type: ignore[arg-type] # pyright: ignore[reportArgumentType] + left.radd(i) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.radd(r0), "pd.Series[str]"), pd.Series, str) check(assert_type(left.radd(r1), "pd.Series[str]"), pd.Series, str) @@ -96,7 +96,7 @@ def test_add_numpy_array() -> None: check(assert_type(left.add(r0), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: - left.radd(i) # type: ignore[arg-type] # pyright: ignore[reportArgumentType] + left.radd(i) # type: ignore[arg-type] # pyright: ignore[reportArgumentType, reportCallIssue] check(assert_type(left.radd(r0), "pd.Series[str]"), pd.Series, str) @@ -118,5 +118,5 @@ def test_add_pd_series() -> None: check(assert_type(left.add(r0), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: - left.radd(i) # type: ignore[arg-type] # pyright: ignore[reportArgumentType] + left.radd(i) # type: ignore[arg-type] # pyright: ignore[reportArgumentType, reportCallIssue] check(assert_type(left.radd(r0), "pd.Series[str]"), pd.Series, str)