Skip to content

Commit 8823cee

Browse files
authored
fix(multiplication): #1413 disallow bool times string (#1416)
Revert "fix(comment): pandas-dev/pandas#62595 #1397 (comment)" This reverts commit 5da6b1c.
1 parent 1cdecd9 commit 8823cee

File tree

4 files changed

+93
-127
lines changed

4 files changed

+93
-127
lines changed

pandas-stubs/core/indexes/base.pyi

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -784,21 +784,18 @@ class Index(IndexOpsMixin[S1]):
784784
@overload
785785
def __mul__(
786786
self: Index[_str],
787-
other: np_ndarray_float | np_ndarray_complex | np_ndarray_dt | np_ndarray_td,
787+
other: (
788+
np_ndarray_bool
789+
| np_ndarray_float
790+
| np_ndarray_complex
791+
| np_ndarray_dt
792+
| np_ndarray_td
793+
),
788794
) -> Never: ...
789-
# pandas-dev/pandas#62595: we may want to support Series[str] * bool
790-
# also in 3.x
791795
@overload
792796
def __mul__(
793797
self: Index[_str],
794-
other: (
795-
int
796-
| Sequence[int]
797-
| np_ndarray_bool
798-
| np_ndarray_anyint
799-
| Index[bool]
800-
| Index[int]
801-
),
798+
other: Just[int] | Sequence[Just[int]] | np_ndarray_anyint | Index[int],
802799
) -> Index[_str]: ...
803800
@overload
804801
def __mul__(self: Index[T_INT], other: bool | Sequence[bool]) -> Index[T_INT]: ...
@@ -877,21 +874,18 @@ class Index(IndexOpsMixin[S1]):
877874
@overload
878875
def __rmul__(
879876
self: Index[_str],
880-
other: np_ndarray_float | np_ndarray_complex | np_ndarray_dt | np_ndarray_td,
877+
other: (
878+
np_ndarray_bool
879+
| np_ndarray_float
880+
| np_ndarray_complex
881+
| np_ndarray_dt
882+
| np_ndarray_td
883+
),
881884
) -> Never: ...
882-
# pandas-dev/pandas#62595: we may want to support Series[str] * bool
883-
# also in 3.x
884885
@overload
885886
def __rmul__(
886887
self: Index[_str],
887-
other: (
888-
int
889-
| Sequence[int]
890-
| np_ndarray_bool
891-
| np_ndarray_anyint
892-
| Index[bool]
893-
| Index[int]
894-
),
888+
other: Just[int] | Sequence[Just[int]] | np_ndarray_anyint | Index[int],
895889
) -> Index[_str]: ...
896890
@overload
897891
def __rmul__(self: Index[T_INT], other: bool | Sequence[bool]) -> Index[T_INT]: ...

pandas-stubs/core/series.pyi

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2586,21 +2586,22 @@ class Series(IndexOpsMixin[S1], NDFrame):
25862586
@overload
25872587
def __mul__(
25882588
self: Series[_str],
2589-
other: np_ndarray_float | np_ndarray_complex | np_ndarray_dt | np_ndarray_td,
2589+
other: (
2590+
np_ndarray_bool
2591+
| np_ndarray_float
2592+
| np_ndarray_complex
2593+
| np_ndarray_dt
2594+
| np_ndarray_td
2595+
),
25902596
) -> Never: ...
2591-
# pandas-dev/pandas#62595: we may want to support Series[str] * bool
2592-
# also in 3.x
25932597
@overload
25942598
def __mul__(
25952599
self: Series[_str],
25962600
other: (
2597-
int
2598-
| Sequence[int]
2599-
| np_ndarray_bool
2601+
Just[int]
2602+
| Sequence[Just[int]]
26002603
| np_ndarray_anyint
2601-
| Index[bool]
26022604
| Index[int]
2603-
| Series[bool]
26042605
| Series[int]
26052606
),
26062607
) -> Series[_str]: ...
@@ -2696,19 +2697,14 @@ class Series(IndexOpsMixin[S1], NDFrame):
26962697
fill_value: float | None = None,
26972698
axis: AxisIndex | None = 0,
26982699
) -> Series[Timedelta]: ...
2699-
# pandas-dev/pandas#62595: we may want to support Series[str] * bool
2700-
# also in 3.x
27012700
@overload
27022701
def mul(
27032702
self: Series[_str],
27042703
other: (
2705-
int
2706-
| Sequence[int]
2707-
| np_ndarray_bool
2704+
Just[int]
2705+
| Sequence[Just[int]]
27082706
| np_ndarray_anyint
2709-
| Index[bool]
27102707
| Index[int]
2711-
| Series[bool]
27122708
| Series[int]
27132709
),
27142710
level: Level | None = None,
@@ -2843,21 +2839,22 @@ class Series(IndexOpsMixin[S1], NDFrame):
28432839
@overload
28442840
def __rmul__(
28452841
self: Series[_str],
2846-
other: np_ndarray_float | np_ndarray_complex | np_ndarray_dt | np_ndarray_td,
2842+
other: (
2843+
np_ndarray_bool
2844+
| np_ndarray_float
2845+
| np_ndarray_complex
2846+
| np_ndarray_dt
2847+
| np_ndarray_td
2848+
),
28472849
) -> Never: ...
2848-
# pandas-dev/pandas#62595: we may want to support Series[str] * bool
2849-
# also in 3.x
28502850
@overload
28512851
def __rmul__(
28522852
self: Series[_str],
28532853
other: (
2854-
int
2855-
| Sequence[int]
2856-
| np_ndarray_bool
2854+
Just[int]
2855+
| Sequence[Just[int]]
28572856
| np_ndarray_anyint
2858-
| Index[bool]
28592857
| Index[int]
2860-
| Series[bool]
28612858
| Series[int]
28622859
),
28632860
) -> Series[_str]: ...
@@ -2955,19 +2952,14 @@ class Series(IndexOpsMixin[S1], NDFrame):
29552952
fill_value: float | None = None,
29562953
axis: AxisIndex | None = 0,
29572954
) -> Series[Timedelta]: ...
2958-
# pandas-dev/pandas#62595: we may want to support Series[str] * bool
2959-
# also in 3.x
29602955
@overload
29612956
def rmul(
29622957
self: Series[_str],
29632958
other: (
2964-
int
2965-
| Sequence[int]
2966-
| np_ndarray_bool
2959+
Just[int]
2960+
| Sequence[Just[int]]
29672961
| np_ndarray_anyint
2968-
| Index[bool]
29692962
| Index[int]
2970-
| Series[bool]
29712963
| Series[int]
29722964
),
29732965
level: Level | None = None,

tests/indexes/arithmetic/str/test_mul.py

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
)
1515

1616
from tests import (
17-
PD_LTE_23,
1817
TYPE_CHECKING_INVALID_USAGE,
1918
check,
2019
)
@@ -32,19 +31,17 @@ def test_mul_py_scalar(left: "pd.Index[str]") -> None:
3231
b, i, f, c = True, 1, 1.0, 1j
3332
s, d = datetime(2025, 9, 27), timedelta(seconds=1)
3433

35-
# pandas-dev/pandas#62595: we may want to support Series[str] * bool
36-
# also in 3.x
37-
if PD_LTE_23:
38-
check(assert_type(left * b, "pd.Index[str]"), pd.Index, str)
34+
if TYPE_CHECKING_INVALID_USAGE:
35+
_00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
3936
check(assert_type(left * i, "pd.Index[str]"), pd.Index, str)
4037
if TYPE_CHECKING_INVALID_USAGE:
4138
_02 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
4239
_03 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
4340
_04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
4441
_05 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
4542

46-
if PD_LTE_23:
47-
check(assert_type(b * left, "pd.Index[str]"), pd.Index, str)
43+
if TYPE_CHECKING_INVALID_USAGE:
44+
_10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
4845
check(assert_type(i * left, "pd.Index[str]"), pd.Index, str)
4946
if TYPE_CHECKING_INVALID_USAGE:
5047
_12 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
@@ -59,19 +56,17 @@ def test_mul_py_sequence(left: "pd.Index[str]") -> None:
5956
s = [datetime(2025, 9, d) for d in (27, 28, 29)]
6057
d = [timedelta(seconds=s + 1) for s in range(3)]
6158

62-
# pandas-dev/pandas#62595: we may want to support Series[str] * bool
63-
# also in 3.x
64-
if PD_LTE_23:
65-
check(assert_type(left * b, "pd.Index[str]"), pd.Index, str)
59+
if TYPE_CHECKING_INVALID_USAGE:
60+
_00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
6661
check(assert_type(left * i, "pd.Index[str]"), pd.Index, str)
6762
if TYPE_CHECKING_INVALID_USAGE:
6863
_02 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
6964
_03 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
7065
_04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
7166
_05 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
7267

73-
if PD_LTE_23:
74-
check(assert_type(b * left, "pd.Index[str]"), pd.Index, str)
68+
if TYPE_CHECKING_INVALID_USAGE:
69+
_10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
7570
check(assert_type(i * left, "pd.Index[str]"), pd.Index, str)
7671
if TYPE_CHECKING_INVALID_USAGE:
7772
_12 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
@@ -89,10 +84,8 @@ def test_mul_numpy_array(left: "pd.Index[str]") -> None:
8984
s = np.array([np.datetime64(f"2025-09-{d}") for d in (27, 28, 29)], np.datetime64)
9085
d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64)
9186

92-
# pandas-dev/pandas#62595: we may want to support Series[str] * bool
93-
# also in 3.x
94-
if PD_LTE_23:
95-
check(assert_type(left * b, "pd.Index[str]"), pd.Index, str)
87+
if TYPE_CHECKING_INVALID_USAGE:
88+
assert_type(left * b, Never)
9689
check(assert_type(left * i, "pd.Index[str]"), pd.Index, str)
9790
if TYPE_CHECKING_INVALID_USAGE:
9891
assert_type(left * f, Never)
@@ -103,8 +96,8 @@ def test_mul_numpy_array(left: "pd.Index[str]") -> None:
10396
# `numpy` typing gives the corresponding `ndarray`s in the static type
10497
# checking, where our `__rmul__` cannot override. At runtime, they return
10598
# `Index` with the correct element type.
106-
if PD_LTE_23:
107-
check(assert_type(b * left, "npt.NDArray[np.bool_]"), pd.Index, str)
99+
if TYPE_CHECKING_INVALID_USAGE:
100+
assert_type(b * left, "npt.NDArray[np.bool_]")
108101
check(assert_type(i * left, "npt.NDArray[np.int64]"), pd.Index, str)
109102
if TYPE_CHECKING_INVALID_USAGE:
110103
assert_type(f * left, "npt.NDArray[np.float64]")
@@ -122,19 +115,17 @@ def test_mul_pd_index(left: "pd.Index[str]") -> None:
122115
s = pd.Index([datetime(2025, 9, d) for d in (27, 28, 29)])
123116
d = pd.Index([timedelta(seconds=s + 1) for s in range(3)])
124117

125-
# pandas-dev/pandas#62595: we may want to support Series[str] * bool
126-
# also in 3.x
127-
if PD_LTE_23:
128-
check(assert_type(left * b, "pd.Index[str]"), pd.Index, str)
118+
if TYPE_CHECKING_INVALID_USAGE:
119+
_00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
129120
check(assert_type(left * i, "pd.Index[str]"), pd.Index, str)
130121
if TYPE_CHECKING_INVALID_USAGE:
131122
_02 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
132123
_03 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
133124
_04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
134125
_05 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
135126

136-
if PD_LTE_23:
137-
check(assert_type(b * left, "pd.Index[str]"), pd.Index, str)
127+
if TYPE_CHECKING_INVALID_USAGE:
128+
_10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue]
138129
check(assert_type(i * left, "pd.Index[str]"), pd.Index, str)
139130
if TYPE_CHECKING_INVALID_USAGE:
140131
_12 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue]

0 commit comments

Comments
 (0)