Skip to content
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

Issues related to numpy #18343

Open
hauntsaninja opened this issue Dec 26, 2024 · 7 comments
Open

Issues related to numpy #18343

hauntsaninja opened this issue Dec 26, 2024 · 7 comments
Labels
meta Issues tracking a broad area of work

Comments

@hauntsaninja
Copy link
Collaborator

This can be a tracking issue.

See also numpy/numpy#27957

@hauntsaninja hauntsaninja added the bug mypy got something wrong label Dec 26, 2024
@hauntsaninja hauntsaninja added meta Issues tracking a broad area of work and removed bug mypy got something wrong labels Dec 27, 2024
@hauntsaninja
Copy link
Collaborator Author

PR adding mypy_primer to numpy's CI: numpy/numpy#28073

@hauntsaninja
Copy link
Collaborator Author

PR fixing a crash when using numpy with weird import following settings: #18351

@hauntsaninja
Copy link
Collaborator Author

hauntsaninja commented Dec 28, 2024

PR improving diagnostics for some case someone ran into using numpy: #18352

@jorenham
Copy link

Not sure if this has been reported before, but the following line is causing stubtest to crash with numpy>=2.2.0 in case you have an empty numpy array as argument default (which is what least scipy==1.14.1 does):

if runtime_arg.default != inspect.Parameter.empty:

Because since NumPy 2.2.0, ndarray.__bool__ will raise if the array is empty. And the reason why __bool__ gets called, is because ndarray.__ne__ returns another array with np.bool dtype of the same shape:

>>> import numpy as np
>>> np.__version__
'2.2.0'
>>> a = np.array([])
>>> a
array([], dtype=float64)
>>> a == object()  # numpy "vectorizes" the `==` over each element
array([], dtype=bool)
>>> bool(a == object())
Traceback (most recent call last):
  File "<python-input-24>", line 1, in <module>
    bool(a == object())
    ~~~~^^^^^^^^^^^^^^^
ValueError: The truth value of an empty array is ambiguous. Use `array.size > 0` to check that an array is not empty.

So when stubtest encounters a def f(a=np.array([])): ... (on the .py side), stubtest will crash:

$ stubtest --mypy-config-file=pyproject.toml --allowlist=.mypyignore --ignore-unused-allowlist scipy
Traceback (most recent call last):
  File "/home/runner/work/scipy-stubs/scipy-stubs/.venv/bin/stubtest", line [8](https://github.com/jorenham/scipy-stubs/actions/runs/12246812991/job/34163454128?pr=288#step:7:9), in <module>
    sys.exit(main())
             ~~~~^^
  File "/home/runner/work/scipy-stubs/scipy-stubs/.venv/lib/python3.13/site-packages/mypy/stubtest.py", line 20[9](https://github.com/jorenham/scipy-stubs/actions/runs/12246812991/job/34163454128?pr=288#step:7:10)8, in main
    return test_stubs(parse_options(sys.argv[1:]))
  File "/home/runner/work/scipy-stubs/scipy-stubs/.venv/lib/python3.13/site-packages/mypy/stubtest.py", line 1971, in test_stubs
    for error in test_module(module):
                 ~~~~~~~~~~~^^^^^^^^
  File "/home/runner/work/scipy-stubs/scipy-stubs/.venv/lib/python3.13/site-packages/mypy/stubtest.py", line 247, in test_module
    yield from verify(stub, runtime, [module_name])
  File "/home/runner/work/scipy-stubs/scipy-stubs/.venv/lib/python3.13/site-packages/mypy/stubtest.py", line 423, in verify_mypyfile
    yield from verify(stub_entry, runtime_entry, object_path + [entry])
  File "/home/runner/work/scipy-stubs/scipy-stubs/.venv/lib/python3.13/site-packages/mypy/stubtest.py", line 578, in verify_typeinfo
    yield from verify(stub_to_verify, runtime_attr, object_path + [entry])
  File "/home/runner/work/scipy-stubs/scipy-stubs/.venv/lib/python3.13/site-packages/mypy/stubtest.py", line [10](https://github.com/jorenham/scipy-stubs/actions/runs/12246812991/job/34163454128?pr=288#step:7:11)64, in verify_funcitem
    for message in _verify_signature(stub_sig, runtime_sig, function_name=stub.name):
                   ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/runner/work/scipy-stubs/scipy-stubs/.venv/lib/python3.[13](https://github.com/jorenham/scipy-stubs/actions/runs/12246812991/job/34163454128?pr=288#step:7:14)/site-packages/mypy/stubtest.py", line 902, in _verify_signature
    yield from _verify_arg_default_value(stub_arg, runtime_arg)
  File "/home/runner/work/scipy-stubs/scipy-stubs/.venv/lib/python3.13/site-packages/mypy/stubtest.py", line 664, in _verify_arg_default_value
    if runtime_arg.default != inspect.Parameter.empty:
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: The truth value of an empty array is ambiguous. Use `array.size > 0` to check that an array is not empty.
Error: Process completed with exit code 1.

Luckily, fixing this is just a matter of replacing != with is not when comparing against inspect.Parameter.empty (which happens in at least 2 two other places in mypy/stubtest.py as well, btw).

I could scrape together a PR if you'd like, but that could take some time (of which I don't have a lot the coming week) as I don't have a local dev env for mypy setup at the moment. And I can imagine that's more mypy-savvy could probably fix this in a coffee break on their nokia 3310 (assuming they don't get distracted and end up playing snake 2, of course). Anyway, I wouldn't mind either way, so let me know 🤷🏻.

@hamdanal
Copy link
Collaborator

Not sure if this has been reported before, but the following line is causing stubtest to crash with numpy>=2.2.0 in case you have an empty numpy array as argument default (which is what least scipy==1.14.1 does):

Thanks for the report, fix is here #18353

@jorenham

This comment was marked as resolved.

@jorenham
Copy link

jorenham commented Jan 5, 2025

It's not possible to annotate the following behavior:

>>> class Spam: ...
>>> np.object_(Spam())
<__main__.Spam object at 0x7f536d7b5160>

And it leads to incorrectly inferred types

class Spam: ...
reveal_type(np.object_(Spam()))   # numpy.object_  (wrong; should be `Spam`)

Pyright correctly reports Type of "np.object_(Spam())" is "Spam".


The other numpy "scalar" constructors either return an instance of themselves, or an ndarray, dependening on the input. For example:

>>> np.int8(42)
np.int8(42)
>>> np.int8([42])
array([42], dtype=int8)

The bare minimum stub looks like

class int8:
    @overload
    def __new__(cls, x: int = 0, /) -> Self: ...
    @overload
    def __new__(cls, x: Sequence[int], /) -> np.ndarray[tuple[int], np.dtype[np.int8]]: ...

But a false positive (according to the typing spec) is reported:

Incompatible return type for "__new__" (returns "ndarray[tuple[int], dtype[signedinteger[_8Bit]]]", but must return a subtype of "int8")

But even so, the second overload isn't completely ignored, because the following isn't reported as an error:

reveal_type(int8(42))  # int8  (correct)
reveal_type(int8([42]))  # int8  (wrong; should be `numpy.ndarray`)

So it's as if the return type of second __new__ overload is ignored, and Self is used instead 🤔


I believe that #15182 is at least in part responsible for this behavior.


Oh and you might already know this, but this is also blocking a typeshed fix for (at least) builtins.reversed annotations (python/typeshed#11646). So the amount of people that will be happy once this is resolved isn't limited to the numpy community :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
meta Issues tracking a broad area of work
Projects
None yet
Development

No branches or pull requests

3 participants