Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ types = [
basedpyright = [
{ include-group = "numpy" },
{ include-group = "types" },
"basedpyright==1.31.3", # trait broke divmod in 1.1.404
"basedpyright==1.31.4",
]
mypy = [
{ include-group = "types" },
Expand Down
808 changes: 404 additions & 404 deletions src/numpy-stubs/@test/generated/ndarray_divmod.pyi

Large diffs are not rendered by default.

244 changes: 122 additions & 122 deletions src/numpy-stubs/@test/generated/scalar_ops_modular.pyi

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions src/numpy-stubs/@test/runtime/legacy/mod.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
td % AR2
AR2 % td

divmod(td, td)
divmod(td, td) # pyright: ignore[reportArgumentType, reportCallIssue] # microsoft/pyright#10899
divmod(td, AR2)
divmod(AR2, td)

Expand Down Expand Up @@ -84,7 +84,7 @@

divmod(i8, b)
divmod(i8, i)
divmod(i8, f)
divmod(i8, f) # pyright: ignore[reportArgumentType, reportCallIssue] # microsoft/pyright#10899
divmod(i8, i4)
divmod(i8, i8)
divmod(i8, f8)
Expand Down Expand Up @@ -113,7 +113,7 @@
divmod(i4, i8)
divmod(f4, i8)
divmod(f4, i4)
divmod(AR, i8)
divmod(AR, i8) # pyright: ignore[reportArgumentType, reportCallIssue] # microsoft/pyright#10899

# float

Expand Down Expand Up @@ -146,4 +146,4 @@
divmod(f8, f8)
divmod(f4, f8)
divmod(f4, f4)
divmod(AR, f8)
divmod(AR, f8) # pyright: ignore[reportArgumentType, reportCallIssue] # microsoft/pyright#10899
2 changes: 1 addition & 1 deletion src/numpy-stubs/@test/runtime/legacy/simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def iterable_func(x: Iterable[object]) -> Iterable[object]:
1 % nonzero_array
array %= 1

divmod(array, 1)
divmod(array, 1) # pyright: ignore[reportArgumentType, reportCallIssue] # microsoft/pyright#10899
divmod(1, nonzero_array)

array**1
Expand Down
7 changes: 5 additions & 2 deletions src/numpy-stubs/@test/static/accept/arithmetic.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ AR_Any: _nt.Array

# Time structures

# NOTE: The pyright ignores are the consequence of a pernicious bug in pyright
# (microsoft/pyright#9896, microsoft/pyright#10849, microsoft/pyright#10899)

assert_type(m8 // m8, np.int64)
assert_type(m8 % m8, np.timedelta64)
assert_type(divmod(m8, m8), tuple[np.int64, np.timedelta64])
assert_type(divmod(m8, m8), tuple[np.int64, np.timedelta64]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]

assert_type(M8_none + m8, np.datetime64[None])
assert_type(M8_none + i, np.datetime64[None])
Expand Down Expand Up @@ -54,7 +57,7 @@ assert_type(m8_delta - delta, dt.timedelta)
assert_type(m8_delta / delta, float)
assert_type(m8_delta // delta, int)
assert_type(m8_delta % delta, dt.timedelta)
assert_type(divmod(m8_delta, delta), tuple[int, dt.timedelta])
assert_type(divmod(m8_delta, delta), tuple[int, dt.timedelta]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]

# Any

Expand Down
4 changes: 2 additions & 2 deletions src/numpy-stubs/@test/static/accept/lib_function_base.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@ assert_type(np.trapezoid(AR_LIKE_c), np.complexfloating)
assert_type(np.trapezoid(AR_LIKE_c, AR_LIKE_f), np.complexfloating)
assert_type(np.trapezoid(AR_LIKE_f, AR_LIKE_c), np.complexfloating)
# pyright bug: https://github.com/microsoft/pyright/issues/9896
assert_type(np.trapezoid(AR_LIKE_O), float) # pyright: ignore[reportAssertTypeFailure]
assert_type(np.trapezoid(AR_LIKE_O, AR_LIKE_f), float) # pyright: ignore[reportAssertTypeFailure]
assert_type(np.trapezoid(AR_LIKE_O), float)
assert_type(np.trapezoid(AR_LIKE_O, AR_LIKE_f), float)
assert_type(np.trapezoid(AR_i8), np.float64 | _nt.Array[np.float64])
assert_type(np.trapezoid(AR_i8, AR_i8), np.float64 | _nt.Array[np.float64])
assert_type(np.trapezoid(AR_f8), np.float64 | _nt.Array[np.float64])
Expand Down
55 changes: 29 additions & 26 deletions src/numpy-stubs/@test/static/accept/mod.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -46,22 +46,25 @@ assert_type(m_td % m_td, np.timedelta64[dt.timedelta | None])
assert_type(AR_m % m, _nt.Array[np.timedelta64])
assert_type(m % AR_m, _nt.Array[np.timedelta64])

# NOTE: `builtins.divmod` cannot be used because of
# https://github.com/microsoft/pyright/issues/9896

assert_type(divmod(m, m), tuple[np.int64, np.timedelta64])
assert_type(m.__divmod__(m_nat), tuple[np.int64, np.timedelta64[None]]) # noqa: PLC2801
assert_type(m.__divmod__(m_int0), tuple[np.int64, np.timedelta64[None]]) # noqa: PLC2801
assert_type(m.__divmod__(m_int), tuple[np.int64, np.timedelta64[int | None]]) # noqa: PLC2801
assert_type(m_nat.__divmod__(m), tuple[np.int64, np.timedelta64[None]]) # noqa: PLC2801
assert_type(m_int.__divmod__(m_nat), tuple[np.int64, np.timedelta64[None]]) # noqa: PLC2801
assert_type(m_int.__divmod__(m_int0), tuple[np.int64, np.timedelta64[None]]) # noqa: PLC2801
assert_type(m_int.__divmod__(m_int), tuple[np.int64, np.timedelta64[int | None]]) # noqa: PLC2801
assert_type(m_int.__divmod__(m_td), tuple[np.int64, np.timedelta64[int | None]]) # noqa: PLC2801
assert_type(m_td.__divmod__(m_nat), tuple[np.int64, np.timedelta64[None]]) # noqa: PLC2801
assert_type(m_td.__divmod__(m_int0), tuple[np.int64, np.timedelta64[None]]) # noqa: PLC2801
assert_type(m_td.__divmod__(m_int), tuple[np.int64, np.timedelta64[int | None]]) # noqa: PLC2801
assert_type(m_td.__divmod__(m_td), tuple[np.int64, np.timedelta64[dt.timedelta | None]]) # noqa: PLC2801
# NOTE: The pyright ignores are the consequence of a pernicious bug in pyright
# (microsoft/pyright#9896, microsoft/pyright#10849, microsoft/pyright#10899) that
# causes incorrect behavior in certain functions that accept generic protocols with
# overloaded methods. Even though mypy also isn't fully correct here, it will at least
# not falsely reject valid calls, and has no problems with any of the following tests.

assert_type(divmod(m, m), tuple[np.int64, np.timedelta64]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
assert_type(divmod(m, m_nat), tuple[np.int64, np.timedelta64[None]])
assert_type(divmod(m, m_int0), tuple[np.int64, np.timedelta64[None]])
assert_type(divmod(m, m_int), tuple[np.int64, np.timedelta64[int | None]]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
assert_type(divmod(m_nat, m), tuple[np.int64, np.timedelta64[None]])
assert_type(divmod(m_int, m_nat), tuple[np.int64, np.timedelta64[None]])
assert_type(divmod(m_int, m_int0), tuple[np.int64, np.timedelta64[None]])
assert_type(divmod(m_int, m_int), tuple[np.int64, np.timedelta64[int | None]]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
assert_type(divmod(m_int, m_td), tuple[np.int64, np.timedelta64[int | None]]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
assert_type(divmod(m_td, m_nat), tuple[np.int64, np.timedelta64[None]])
assert_type(divmod(m_td, m_int0), tuple[np.int64, np.timedelta64[None]])
assert_type(divmod(m_td, m_int), tuple[np.int64, np.timedelta64[int | None]]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
assert_type(divmod(m_td, m_td), tuple[np.int64, np.timedelta64[dt.timedelta | None]]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]

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

assert_type(divmod(b_, b_), tuple[np.int8, np.int8])
assert_type(divmod(b_, b), tuple[np.int8, np.int8])
assert_type(divmod(b_, i), tuple[np.intp, np.intp])
assert_type(divmod(b_, f), tuple[np.float64, np.float64])
assert_type(divmod(b_, i), tuple[np.intp, np.intp]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
assert_type(divmod(b_, f), tuple[np.float64, np.float64]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
assert_type(divmod(b_, i8), tuple[np.int64, np.int64])
assert_type(divmod(b_, u8), tuple[np.uint64, np.uint64])
assert_type(divmod(b_, f8), tuple[np.float64, np.float64])
Expand All @@ -95,8 +98,8 @@ assert_type(f8 % b_, np.float64)
assert_type(AR_b % b_, _nt.Array[np.int8])

assert_type(divmod(b_, b), tuple[np.int8, np.int8])
assert_type(divmod(b_, i), tuple[np.intp, np.intp])
assert_type(divmod(b_, f), tuple[np.float64, np.float64])
assert_type(divmod(b_, i), tuple[np.intp, np.intp]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
assert_type(divmod(b_, f), tuple[np.float64, np.float64]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
assert_type(divmod(b_, i8), tuple[np.int64, np.int64])
assert_type(divmod(b_, u8), tuple[np.uint64, np.uint64])
assert_type(divmod(b_, f8), tuple[np.float64, np.float64])
Expand All @@ -117,7 +120,7 @@ assert_type(i8 % AR_b, _nt.Array[np.int64])

assert_type(divmod(i8, b), tuple[np.int64, np.int64])
assert_type(divmod(i8, i), tuple[np.int64, np.int64])
assert_type(divmod(i8, f), tuple[np.float64, np.float64])
assert_type(divmod(i8, f), tuple[np.float64, np.float64]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
assert_type(divmod(i8, i4), tuple[np.int64, np.int64])
assert_type(divmod(i8, i8), tuple[np.int64, np.int64])
assert_type(divmod(i8, f8), tuple[np.float64, np.float64])
Expand All @@ -136,14 +139,14 @@ assert_type(f4 % i4, np.float64)
assert_type(AR_b % i8, _nt.Array[np.int64])

assert_type(divmod(i8, b), tuple[np.int64, np.int64])
assert_type(divmod(i8, f), tuple[np.float64, np.float64])
assert_type(divmod(i8, f), tuple[np.float64, np.float64]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
assert_type(divmod(i8, i8), tuple[np.int64, np.int64])
assert_type(divmod(i8, f8), tuple[np.float64, np.float64])
assert_type(divmod(i8, i4), tuple[np.int64, np.int64])
assert_type(divmod(i4, i8), tuple[np.int64, np.int64])
assert_type(divmod(f4, i8), tuple[np.float64, np.float64])
assert_type(divmod(f4, i4), tuple[np.float64, np.float64])
assert_type(divmod(AR_b, i8), tuple[_nt.Array[np.int64], _nt.Array[np.int64]])
assert_type(divmod(AR_b, i8), tuple[_nt.Array[np.int64], _nt.Array[np.int64]]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]

# float

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

assert_type(b % f8, np.float64)
assert_type(f % f8, np.float64) # pyright: ignore[reportAssertTypeFailure] # pyright incorrectly infers `builtins.float`
assert_type(f % f8, np.float64) # pyright: ignore[reportAssertTypeFailure] # pyright incorrectly infers `float`
assert_type(f8 % f8, np.float64)
assert_type(f8 % f8, np.float64)
assert_type(f4 % f4, np.float32)
Expand All @@ -170,6 +173,6 @@ assert_type(AR_b % f8, _nt.Array[np.float64])
assert_type(divmod(b, f8), tuple[np.float64, np.float64])
assert_type(divmod(f8, f8), tuple[np.float64, np.float64])
assert_type(divmod(f4, f4), tuple[np.float32, np.float32])
assert_type(divmod(f, f8), tuple[np.float64, np.float64]) # pyright: ignore[reportAssertTypeFailure]
assert_type(divmod(f, f8), tuple[np.float64, np.float64]) # pyright: ignore[reportAssertTypeFailure] # pyright incorrectly infers `tuple[float, float]`
assert_type(divmod(f4, f8), tuple[np.float64, np.float64])
assert_type(divmod(AR_b, f8), tuple[_nt.Array[np.float64], _nt.Array[np.float64]])
assert_type(divmod(AR_b, f8), tuple[_nt.Array[np.float64], _nt.Array[np.float64]]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue]
5 changes: 3 additions & 2 deletions src/numpy-stubs/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3805,14 +3805,15 @@ class bool_(generic[_BoolItemT_co], Generic[_BoolItemT_co]):
def __rmod__(self, x: _nt.JustFloat, /) -> float64: ...

# keep in sync with __mod__
@overload
def __divmod__(self, x: _RealNumberT, /) -> _Tuple2[_RealNumberT]: ...
# NOTE: The overload order helps avoid some errors from microsoft/pyright#10899.
@overload
def __divmod__(self, x: py_bool | bool_, /) -> _Tuple2[int8]: ...
@overload
def __divmod__(self, x: _nt.JustInt, /) -> _Tuple2[intp]: ...
@overload
def __divmod__(self, x: _nt.JustFloat, /) -> _Tuple2[float64]: ...
@overload
def __divmod__(self, x: _RealNumberT, /) -> _Tuple2[_RealNumberT]: ...

# keep in sync with __rmod__
@overload
Expand Down
50 changes: 48 additions & 2 deletions tool/testgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -1049,10 +1049,23 @@ def _evaluate(self, op: str, lhs: str, rhs: str, /) -> str | None:
return f"tuple[{', '.join(result_exprs)}]" if nout > 1 else result_exprs[0]

def _assert_stmt(self, op: str, lhs: str, rhs: str, /) -> str | None:
expr_eval = op.format(self.names[lhs], self.names[rhs])
# ugly workaround for microsoft/pyright#9896 and microsoft/pyright#10899
if (
op.startswith("divmod")
and "c" not in self.names[lhs] + self.names[rhs]
and (
self.names[rhs].endswith("_py")
or (not self.names[lhs][-1].isdigit() and self.names[rhs][-1].isdigit())
or (self.names[lhs] == "iu" and self.names[rhs] == "u")
or (lhs == rhs == "m")
)
):
expr_eval = f"{self.names[lhs]}.__divmod__({self.names[rhs]})"
else:
expr_eval = op.format(self.names[lhs], self.names[rhs])

# generate rejection test, while avoiding trivial cases
if not (expr_type := self._evaluate(op, lhs, rhs)):
# generate rejection test, while avoiding trivial cases
opname = self.ops[op].__name__.removesuffix("_")
if (
# ignore bitwise ops if neither arg is a bitwise char
Expand Down Expand Up @@ -1321,6 +1334,39 @@ def _op_expr(self, arg_expr: str, /) -> str: ...
@overload
def _op_expr(self, arg_expr_a: str, arg_expr_b: str, /) -> str: ...
def _op_expr(self, /, *arg_exprs: str) -> str:
# ugly workaround for microsoft/pyright#9896 and microsoft/pyright#10899
if self.opname == "divmod":
lhs, rhs = arg_exprs
if (
"c" in {lhs[0], rhs[0]}
or (lhs.startswith("m8") and not rhs.startswith("m8"))
or (not lhs.startswith("m8") and rhs.startswith("m8"))
):
pass
elif (
lhs.endswith("py")
or (
# reflect if rhs is abstract
not rhs.endswith("_py")
and not rhs[1].isdigit()
and lhs[1].isdigit()
)
or (
# reflect if both are abstract and lhs is coercible to to rhs
not rhs.endswith("_py")
and not rhs[1].isdigit()
and not lhs[1].isdigit()
and lhs != rhs
and (
lhs[0]
in rhs.split("_")[0].replace("c", "cf").replace("f", "fui")
)
)
):
return f"{rhs}.__rdivmod__({lhs})"
else:
return f"{lhs}.__divmod__({rhs})"

return self.__op_expr_template.format(*arg_exprs)

def _evaluate_unnop(self, arg: npt.ArrayLike, /) -> np.dtype | None:
Expand Down
12 changes: 6 additions & 6 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading