Skip to content

TYP: np.mod(npt.NDArray, Any) is Any in 2.2.2 while it wasn't in 2.2.1 #28192

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
bersbersbers opened this issue Jan 20, 2025 · 1 comment
Closed

Comments

@bersbersbers
Copy link
Contributor

Describe the issue:

numpy 2.2.2 reveals a different type for np.mod(npt.NDArray, Any) than 2.2.1. This looks like a result of #28176. Please close if this is an intended change.

Reproduce the code example:

from typing import Any

import numpy as np
import numpy.typing as npt


def func(x: npt.NDArray[np.integer[Any]], y: Any) -> None:
    reveal_type(np.mod(x, y))

Error message:

2.2.1: "numpy.ndarray[builtins.tuple[builtins.int, ...], numpy.dtype[Any]]"
2.2.2: "Any"

Python and NumPy Versions:

Numpy 2.2.2 vs 2.2.1

Type-checker version and settings:

mypy 1.14.1 (compiled: yes)

Additional typing packages.

No response

@jorenham
Copy link
Member

Thanks for reporting this!

This actually wasn't intentional. I'm able to reproduce this, but only with mypy, and e.g. Pyright reports the following:

Type of "np.mod(x, y)" is "ndarray[tuple[int, ...], dtype[Any]]"

But I can't explain why mypy is behaving this way. There's only one overload that return Any, and that's the first one. But as you can see, it only accepts scalar-like input, so it shouldn't be relevant in this case.

def __call__(
self,
x1: _ScalarLike_co,
x2: _ScalarLike_co,
/,
out: None = None,
*,
dtype: DTypeLike | None = None,
**kwds: Unpack[_UFunc3Kwargs],
) -> Any: ...
@overload # (array-like, array) -> array
def __call__(
self,
x1: ArrayLike,
x2: NDArray[np.generic],
/,
out: NDArray[np.generic] | tuple[NDArray[np.generic]] | None = None,
*,
dtype: DTypeLike | None = None,
**kwds: Unpack[_UFunc3Kwargs],
) -> NDArray[Any]: ...
@overload # (array, array-like) -> array
def __call__(
self,
x1: NDArray[np.generic],
x2: ArrayLike,
/,
out: NDArray[np.generic] | tuple[NDArray[np.generic]] | None = None,
*,
dtype: DTypeLike | None = None,
**kwds: Unpack[_UFunc3Kwargs],
) -> NDArray[Any]: ...
@overload # (array-like, array-like, out=array) -> array
def __call__(
self,
x1: ArrayLike,
x2: ArrayLike,
/,
out: NDArray[np.generic] | tuple[NDArray[np.generic]],
*,
dtype: DTypeLike | None = None,
**kwds: Unpack[_UFunc3Kwargs],
) -> NDArray[Any]: ...
@overload # (array-like, array-like) -> array | scalar
def __call__(
self,
x1: ArrayLike,
x2: ArrayLike,
/,
out: NDArray[np.generic] | tuple[NDArray[np.generic]] | None = None,
*,
dtype: DTypeLike | None = None,
**kwds: Unpack[_UFunc3Kwargs],
) -> NDArray[Any] | Any: ...

So I would have expected mypy to use the 2nd or 3rd overload instead, and return NDArray[Any], like it did before. Even if it went for the last overload, the return type would be NDArray[Any] | Any, which isn't the same as Any (T | Any is not reducible to Any, according to the typing spec, and is defined to have some specific meaning).


But either way, for the majority of users, I don't expect that this will lead to any issues. In general, I would advise to avoid using Any if you can, as it can lead to undefined behavior, and using it is almost always type-unsafe.

So if you're alright with it, I'll close this issue, as it appears to be caused by a bug in mypy (and only mypy).

@jorenham jorenham added the 57 - Close? Issues which may be closable unless discussion continued label Jan 20, 2025
@jorenham jorenham marked this as a duplicate of #28193 Jan 20, 2025
@jorenham jorenham removed the 57 - Close? Issues which may be closable unless discussion continued label Jan 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants