Skip to content

TYP: mypy believes enumerate returns float64 instead of NDArray #28245

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
matteobrv opened this issue Jan 28, 2025 · 2 comments
Closed

TYP: mypy believes enumerate returns float64 instead of NDArray #28245

matteobrv opened this issue Jan 28, 2025 · 2 comments

Comments

@matteobrv
Copy link

Describe the issue:

In the code example a is [[1. 1.] [1. 1.]] and ai is [1. 1.], a one-dimensional array. However, mypy flags the call to foo(ai) and complains that ai is not an NDArray. The snippet below illustrates the issue focusing on enumerate, but I actually encountered the same behavior with zip.

I tested the same logic with numpy: 2.1.3 and mypy 1.14.1, and there were no errors.

Reproduce the code example:

import numpy as np
import numpy.typing as npt

def foo(x: npt.NDArray[np.float64]) -> None:
    print(x)

a = np.ones([2, 2])

for _, ai in enumerate(a):
    foo(ai)

Error message:

error: Argument 1 to "foo" has incompatible type "float64"; expected "ndarray[tuple[int, ...], dtype[float64]]"  [arg-type]

Python and NumPy Versions:

numpy: 2.2.2
Python: 3.12.8 (main, Jan 22 2025, 21:56:05) [GCC 11.4.0]

Type-checker version and settings:

mypy 1.14.1 (compiled: yes)
mypy myproblem.py

Additional typing packages.

No response

@jorenham
Copy link
Member

I can reproduce this on the main branch, but only with mypy:

import numpy as np
import numpy.typing as npt

a: npt.NDArray[np.float64]
reveal_type(iter(a))

Mypy 1.14.1:

Revealed type is "typing.Iterator[numpy.float64]"

Pyright 1.1.392:

Type of "iter(a)" is "Iterator[Any]"

This is caused by a bug in mypy (probably python/mypy#14070).

To see why I think mypy is behaving incorrectly, you could take a look at the definition for numpy.ndarray.__iter__:

numpy/numpy/__init__.pyi

Lines 2570 to 2577 in a1fa8e1

@overload # == 1-d & object_
def __iter__(self: ndarray[tuple[int], dtype[object_]], /) -> Iterator[Any]: ...
@overload # == 1-d
def __iter__(self: ndarray[tuple[int], dtype[_SCT]], /) -> Iterator[_SCT]: ...
@overload # >= 2-d
def __iter__(self: ndarray[tuple[int, int, Unpack[tuple[int, ...]]], dtype[_SCT]], /) -> Iterator[NDArray[_SCT]]: ...
@overload # ?-d
def __iter__(self, /) -> Iterator[Any]: ...

The only overload that could return a Iterator[float64], is the second one. This overload requires self to have a shape-type of tuple[int], i.e. it must be 1-d. But the shape-type of a is unspecified, i.e. tuple[int, ...]. But tuple[int, ...] cannot be assigned to tuple[int].
So the only valid overload here, is the last one, which returns Iterator[Any], and is therefore what Pyright infers the return type as.


I don't see any reason why mypy would behave this way,.. So I also don't know how we could work around this. It's probably a good idea to raise this with mypy &mdhash; they have been very helpful recently in fixing numpy-related issues (see python/mypy#18343).

@matteobrv
Copy link
Author

Thanks for taking the time to look into this and suggesting a possible cause of the problem. I've raised the issue with mypy: python/mypy#18566. I'll go ahead and close this issue and continue monitoring the situation on the mypy side.

@jorenham jorenham removed the 57 - Close? Issues which may be closable unless discussion continued label Jan 29, 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