Skip to content

Commit 8383364

Browse files
authored
Merge pull request #708 from numpy/pyright-1.1.405
2 parents ff2f7c9 + d5bc86e commit 8383364

11 files changed

Lines changed: 625 additions & 572 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ types = [
7070
basedpyright = [
7171
{ include-group = "numpy" },
7272
{ include-group = "types" },
73-
"basedpyright==1.31.3", # trait broke divmod in 1.1.404
73+
"basedpyright==1.31.4",
7474
]
7575
mypy = [
7676
{ include-group = "types" },

src/numpy-stubs/@test/generated/ndarray_divmod.pyi

Lines changed: 404 additions & 404 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/numpy-stubs/@test/generated/scalar_ops_modular.pyi

Lines changed: 122 additions & 122 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/numpy-stubs/@test/runtime/legacy/mod.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
td % AR2
2828
AR2 % td
2929

30-
divmod(td, td)
30+
divmod(td, td) # pyright: ignore[reportArgumentType, reportCallIssue] # microsoft/pyright#10899
3131
divmod(td, AR2)
3232
divmod(AR2, td)
3333

@@ -84,7 +84,7 @@
8484

8585
divmod(i8, b)
8686
divmod(i8, i)
87-
divmod(i8, f)
87+
divmod(i8, f) # pyright: ignore[reportArgumentType, reportCallIssue] # microsoft/pyright#10899
8888
divmod(i8, i4)
8989
divmod(i8, i8)
9090
divmod(i8, f8)
@@ -113,7 +113,7 @@
113113
divmod(i4, i8)
114114
divmod(f4, i8)
115115
divmod(f4, i4)
116-
divmod(AR, i8)
116+
divmod(AR, i8) # pyright: ignore[reportArgumentType, reportCallIssue] # microsoft/pyright#10899
117117

118118
# float
119119

@@ -146,4 +146,4 @@
146146
divmod(f8, f8)
147147
divmod(f4, f8)
148148
divmod(f4, f4)
149-
divmod(AR, f8)
149+
divmod(AR, f8) # pyright: ignore[reportArgumentType, reportCallIssue] # microsoft/pyright#10899

src/numpy-stubs/@test/runtime/legacy/simple.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def iterable_func(x: Iterable[object]) -> Iterable[object]:
133133
1 % nonzero_array
134134
array %= 1
135135

136-
divmod(array, 1)
136+
divmod(array, 1) # pyright: ignore[reportArgumentType, reportCallIssue] # microsoft/pyright#10899
137137
divmod(1, nonzero_array)
138138

139139
array**1

src/numpy-stubs/@test/static/accept/arithmetic.pyi

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ AR_Any: _nt.Array
2222

2323
# Time structures
2424

25+
# NOTE: The pyright ignores are the consequence of a pernicious bug in pyright
26+
# (microsoft/pyright#9896, microsoft/pyright#10849, microsoft/pyright#10899)
27+
2528
assert_type(m8 // m8, np.int64)
2629
assert_type(m8 % m8, np.timedelta64)
27-
assert_type(divmod(m8, m8), tuple[np.int64, np.timedelta64])
30+
assert_type(divmod(m8, m8), tuple[np.int64, np.timedelta64]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
2831

2932
assert_type(M8_none + m8, np.datetime64[None])
3033
assert_type(M8_none + i, np.datetime64[None])
@@ -54,7 +57,7 @@ assert_type(m8_delta - delta, dt.timedelta)
5457
assert_type(m8_delta / delta, float)
5558
assert_type(m8_delta // delta, int)
5659
assert_type(m8_delta % delta, dt.timedelta)
57-
assert_type(divmod(m8_delta, delta), tuple[int, dt.timedelta])
60+
assert_type(divmod(m8_delta, delta), tuple[int, dt.timedelta]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
5861

5962
# Any
6063

src/numpy-stubs/@test/static/accept/lib_function_base.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,8 @@ assert_type(np.trapezoid(AR_LIKE_c), np.complexfloating)
182182
assert_type(np.trapezoid(AR_LIKE_c, AR_LIKE_f), np.complexfloating)
183183
assert_type(np.trapezoid(AR_LIKE_f, AR_LIKE_c), np.complexfloating)
184184
# pyright bug: https://github.com/microsoft/pyright/issues/9896
185-
assert_type(np.trapezoid(AR_LIKE_O), float) # pyright: ignore[reportAssertTypeFailure]
186-
assert_type(np.trapezoid(AR_LIKE_O, AR_LIKE_f), float) # pyright: ignore[reportAssertTypeFailure]
185+
assert_type(np.trapezoid(AR_LIKE_O), float)
186+
assert_type(np.trapezoid(AR_LIKE_O, AR_LIKE_f), float)
187187
assert_type(np.trapezoid(AR_i8), np.float64 | _nt.Array[np.float64])
188188
assert_type(np.trapezoid(AR_i8, AR_i8), np.float64 | _nt.Array[np.float64])
189189
assert_type(np.trapezoid(AR_f8), np.float64 | _nt.Array[np.float64])

src/numpy-stubs/@test/static/accept/mod.pyi

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,25 @@ assert_type(m_td % m_td, np.timedelta64[dt.timedelta | None])
4646
assert_type(AR_m % m, _nt.Array[np.timedelta64])
4747
assert_type(m % AR_m, _nt.Array[np.timedelta64])
4848

49-
# NOTE: `builtins.divmod` cannot be used because of
50-
# https://github.com/microsoft/pyright/issues/9896
51-
52-
assert_type(divmod(m, m), tuple[np.int64, np.timedelta64])
53-
assert_type(m.__divmod__(m_nat), tuple[np.int64, np.timedelta64[None]]) # noqa: PLC2801
54-
assert_type(m.__divmod__(m_int0), tuple[np.int64, np.timedelta64[None]]) # noqa: PLC2801
55-
assert_type(m.__divmod__(m_int), tuple[np.int64, np.timedelta64[int | None]]) # noqa: PLC2801
56-
assert_type(m_nat.__divmod__(m), tuple[np.int64, np.timedelta64[None]]) # noqa: PLC2801
57-
assert_type(m_int.__divmod__(m_nat), tuple[np.int64, np.timedelta64[None]]) # noqa: PLC2801
58-
assert_type(m_int.__divmod__(m_int0), tuple[np.int64, np.timedelta64[None]]) # noqa: PLC2801
59-
assert_type(m_int.__divmod__(m_int), tuple[np.int64, np.timedelta64[int | None]]) # noqa: PLC2801
60-
assert_type(m_int.__divmod__(m_td), tuple[np.int64, np.timedelta64[int | None]]) # noqa: PLC2801
61-
assert_type(m_td.__divmod__(m_nat), tuple[np.int64, np.timedelta64[None]]) # noqa: PLC2801
62-
assert_type(m_td.__divmod__(m_int0), tuple[np.int64, np.timedelta64[None]]) # noqa: PLC2801
63-
assert_type(m_td.__divmod__(m_int), tuple[np.int64, np.timedelta64[int | None]]) # noqa: PLC2801
64-
assert_type(m_td.__divmod__(m_td), tuple[np.int64, np.timedelta64[dt.timedelta | None]]) # noqa: PLC2801
49+
# NOTE: The pyright ignores are the consequence of a pernicious bug in pyright
50+
# (microsoft/pyright#9896, microsoft/pyright#10849, microsoft/pyright#10899) that
51+
# causes incorrect behavior in certain functions that accept generic protocols with
52+
# overloaded methods. Even though mypy also isn't fully correct here, it will at least
53+
# not falsely reject valid calls, and has no problems with any of the following tests.
54+
55+
assert_type(divmod(m, m), tuple[np.int64, np.timedelta64]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
56+
assert_type(divmod(m, m_nat), tuple[np.int64, np.timedelta64[None]])
57+
assert_type(divmod(m, m_int0), tuple[np.int64, np.timedelta64[None]])
58+
assert_type(divmod(m, m_int), tuple[np.int64, np.timedelta64[int | None]]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
59+
assert_type(divmod(m_nat, m), tuple[np.int64, np.timedelta64[None]])
60+
assert_type(divmod(m_int, m_nat), tuple[np.int64, np.timedelta64[None]])
61+
assert_type(divmod(m_int, m_int0), tuple[np.int64, np.timedelta64[None]])
62+
assert_type(divmod(m_int, m_int), tuple[np.int64, np.timedelta64[int | None]]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
63+
assert_type(divmod(m_int, m_td), tuple[np.int64, np.timedelta64[int | None]]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
64+
assert_type(divmod(m_td, m_nat), tuple[np.int64, np.timedelta64[None]])
65+
assert_type(divmod(m_td, m_int0), tuple[np.int64, np.timedelta64[None]])
66+
assert_type(divmod(m_td, m_int), tuple[np.int64, np.timedelta64[int | None]]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
67+
assert_type(divmod(m_td, m_td), tuple[np.int64, np.timedelta64[dt.timedelta | None]]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
6568

6669
assert_type(divmod(AR_m, m), tuple[_nt.Array[np.int64], _nt.Array[np.timedelta64]])
6770
assert_type(divmod(m, AR_m), tuple[_nt.Array[np.int64], _nt.Array[np.timedelta64]])
@@ -78,8 +81,8 @@ assert_type(b_ % AR_b, _nt.Array[np.int8])
7881

7982
assert_type(divmod(b_, b_), tuple[np.int8, np.int8])
8083
assert_type(divmod(b_, b), tuple[np.int8, np.int8])
81-
assert_type(divmod(b_, i), tuple[np.intp, np.intp])
82-
assert_type(divmod(b_, f), tuple[np.float64, np.float64])
84+
assert_type(divmod(b_, i), tuple[np.intp, np.intp]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
85+
assert_type(divmod(b_, f), tuple[np.float64, np.float64]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
8386
assert_type(divmod(b_, i8), tuple[np.int64, np.int64])
8487
assert_type(divmod(b_, u8), tuple[np.uint64, np.uint64])
8588
assert_type(divmod(b_, f8), tuple[np.float64, np.float64])
@@ -95,8 +98,8 @@ assert_type(f8 % b_, np.float64)
9598
assert_type(AR_b % b_, _nt.Array[np.int8])
9699

97100
assert_type(divmod(b_, b), tuple[np.int8, np.int8])
98-
assert_type(divmod(b_, i), tuple[np.intp, np.intp])
99-
assert_type(divmod(b_, f), tuple[np.float64, np.float64])
101+
assert_type(divmod(b_, i), tuple[np.intp, np.intp]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
102+
assert_type(divmod(b_, f), tuple[np.float64, np.float64]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
100103
assert_type(divmod(b_, i8), tuple[np.int64, np.int64])
101104
assert_type(divmod(b_, u8), tuple[np.uint64, np.uint64])
102105
assert_type(divmod(b_, f8), tuple[np.float64, np.float64])
@@ -117,7 +120,7 @@ assert_type(i8 % AR_b, _nt.Array[np.int64])
117120

118121
assert_type(divmod(i8, b), tuple[np.int64, np.int64])
119122
assert_type(divmod(i8, i), tuple[np.int64, np.int64])
120-
assert_type(divmod(i8, f), tuple[np.float64, np.float64])
123+
assert_type(divmod(i8, f), tuple[np.float64, np.float64]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
121124
assert_type(divmod(i8, i4), tuple[np.int64, np.int64])
122125
assert_type(divmod(i8, i8), tuple[np.int64, np.int64])
123126
assert_type(divmod(i8, f8), tuple[np.float64, np.float64])
@@ -136,14 +139,14 @@ assert_type(f4 % i4, np.float64)
136139
assert_type(AR_b % i8, _nt.Array[np.int64])
137140

138141
assert_type(divmod(i8, b), tuple[np.int64, np.int64])
139-
assert_type(divmod(i8, f), tuple[np.float64, np.float64])
142+
assert_type(divmod(i8, f), tuple[np.float64, np.float64]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
140143
assert_type(divmod(i8, i8), tuple[np.int64, np.int64])
141144
assert_type(divmod(i8, f8), tuple[np.float64, np.float64])
142145
assert_type(divmod(i8, i4), tuple[np.int64, np.int64])
143146
assert_type(divmod(i4, i8), tuple[np.int64, np.int64])
144147
assert_type(divmod(f4, i8), tuple[np.float64, np.float64])
145148
assert_type(divmod(f4, i4), tuple[np.float64, np.float64])
146-
assert_type(divmod(AR_b, i8), tuple[_nt.Array[np.int64], _nt.Array[np.int64]])
149+
assert_type(divmod(AR_b, i8), tuple[_nt.Array[np.int64], _nt.Array[np.int64]]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
147150

148151
# float
149152

@@ -161,7 +164,7 @@ assert_type(divmod(f4, f4), tuple[np.float32, np.float32])
161164
assert_type(divmod(f8, AR_b), tuple[_nt.Array[np.float64], _nt.Array[np.float64]])
162165

163166
assert_type(b % f8, np.float64)
164-
assert_type(f % f8, np.float64) # pyright: ignore[reportAssertTypeFailure] # pyright incorrectly infers `builtins.float`
167+
assert_type(f % f8, np.float64) # pyright: ignore[reportAssertTypeFailure] # pyright incorrectly infers `float`
165168
assert_type(f8 % f8, np.float64)
166169
assert_type(f8 % f8, np.float64)
167170
assert_type(f4 % f4, np.float32)
@@ -170,6 +173,6 @@ assert_type(AR_b % f8, _nt.Array[np.float64])
170173
assert_type(divmod(b, f8), tuple[np.float64, np.float64])
171174
assert_type(divmod(f8, f8), tuple[np.float64, np.float64])
172175
assert_type(divmod(f4, f4), tuple[np.float32, np.float32])
173-
assert_type(divmod(f, f8), tuple[np.float64, np.float64]) # pyright: ignore[reportAssertTypeFailure]
176+
assert_type(divmod(f, f8), tuple[np.float64, np.float64]) # pyright: ignore[reportAssertTypeFailure] # pyright incorrectly infers `tuple[float, float]`
174177
assert_type(divmod(f4, f8), tuple[np.float64, np.float64])
175-
assert_type(divmod(AR_b, f8), tuple[_nt.Array[np.float64], _nt.Array[np.float64]])
178+
assert_type(divmod(AR_b, f8), tuple[_nt.Array[np.float64], _nt.Array[np.float64]]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]

src/numpy-stubs/__init__.pyi

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3805,14 +3805,15 @@ class bool_(generic[_BoolItemT_co], Generic[_BoolItemT_co]):
38053805
def __rmod__(self, x: _nt.JustFloat, /) -> float64: ...
38063806

38073807
# keep in sync with __mod__
3808-
@overload
3809-
def __divmod__(self, x: _RealNumberT, /) -> _Tuple2[_RealNumberT]: ...
3808+
# NOTE: The overload order helps avoid some errors from microsoft/pyright#10899.
38103809
@overload
38113810
def __divmod__(self, x: py_bool | bool_, /) -> _Tuple2[int8]: ...
38123811
@overload
38133812
def __divmod__(self, x: _nt.JustInt, /) -> _Tuple2[intp]: ...
38143813
@overload
38153814
def __divmod__(self, x: _nt.JustFloat, /) -> _Tuple2[float64]: ...
3815+
@overload
3816+
def __divmod__(self, x: _RealNumberT, /) -> _Tuple2[_RealNumberT]: ...
38163817

38173818
# keep in sync with __rmod__
38183819
@overload

tool/testgen.py

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,10 +1049,23 @@ def _evaluate(self, op: str, lhs: str, rhs: str, /) -> str | None:
10491049
return f"tuple[{', '.join(result_exprs)}]" if nout > 1 else result_exprs[0]
10501050

10511051
def _assert_stmt(self, op: str, lhs: str, rhs: str, /) -> str | None:
1052-
expr_eval = op.format(self.names[lhs], self.names[rhs])
1052+
# ugly workaround for microsoft/pyright#9896 and microsoft/pyright#10899
1053+
if (
1054+
op.startswith("divmod")
1055+
and "c" not in self.names[lhs] + self.names[rhs]
1056+
and (
1057+
self.names[rhs].endswith("_py")
1058+
or (not self.names[lhs][-1].isdigit() and self.names[rhs][-1].isdigit())
1059+
or (self.names[lhs] == "iu" and self.names[rhs] == "u")
1060+
or (lhs == rhs == "m")
1061+
)
1062+
):
1063+
expr_eval = f"{self.names[lhs]}.__divmod__({self.names[rhs]})"
1064+
else:
1065+
expr_eval = op.format(self.names[lhs], self.names[rhs])
10531066

1067+
# generate rejection test, while avoiding trivial cases
10541068
if not (expr_type := self._evaluate(op, lhs, rhs)):
1055-
# generate rejection test, while avoiding trivial cases
10561069
opname = self.ops[op].__name__.removesuffix("_")
10571070
if (
10581071
# ignore bitwise ops if neither arg is a bitwise char
@@ -1321,6 +1334,39 @@ def _op_expr(self, arg_expr: str, /) -> str: ...
13211334
@overload
13221335
def _op_expr(self, arg_expr_a: str, arg_expr_b: str, /) -> str: ...
13231336
def _op_expr(self, /, *arg_exprs: str) -> str:
1337+
# ugly workaround for microsoft/pyright#9896 and microsoft/pyright#10899
1338+
if self.opname == "divmod":
1339+
lhs, rhs = arg_exprs
1340+
if (
1341+
"c" in {lhs[0], rhs[0]}
1342+
or (lhs.startswith("m8") and not rhs.startswith("m8"))
1343+
or (not lhs.startswith("m8") and rhs.startswith("m8"))
1344+
):
1345+
pass
1346+
elif (
1347+
lhs.endswith("py")
1348+
or (
1349+
# reflect if rhs is abstract
1350+
not rhs.endswith("_py")
1351+
and not rhs[1].isdigit()
1352+
and lhs[1].isdigit()
1353+
)
1354+
or (
1355+
# reflect if both are abstract and lhs is coercible to to rhs
1356+
not rhs.endswith("_py")
1357+
and not rhs[1].isdigit()
1358+
and not lhs[1].isdigit()
1359+
and lhs != rhs
1360+
and (
1361+
lhs[0]
1362+
in rhs.split("_")[0].replace("c", "cf").replace("f", "fui")
1363+
)
1364+
)
1365+
):
1366+
return f"{rhs}.__rdivmod__({lhs})"
1367+
else:
1368+
return f"{lhs}.__divmod__({rhs})"
1369+
13241370
return self.__op_expr_template.format(*arg_exprs)
13251371

13261372
def _evaluate_unnop(self, arg: npt.ArrayLike, /) -> np.dtype | None:

0 commit comments

Comments
 (0)