Skip to content
This repository was archived by the owner on May 1, 2025. It is now read-only.

Commit 61c0e70

Browse files
committed
a bug report that deserves a cookie
0 parents  commit 61c0e70

File tree

5 files changed

+208
-0
lines changed

5 files changed

+208
-0
lines changed

.gitignore

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Python-generated files
2+
__pycache__/
3+
*.py[oc]
4+
build/
5+
dist/
6+
wheels/
7+
*.egg-info
8+
9+
# Environment variables
10+
.env
11+
12+
# Virtual environments
13+
.venv
14+
15+
# Cache
16+
.cache/
17+
.mypy_cache/
18+
.pytest_cache/
19+
.ruff_cache/
20+
.tox/
21+
22+
# Docs
23+
site/

README.md

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# Mypy's PEP 561 NumPy issue repro
2+
3+
From <https://mypy.readthedocs.io/en/stable/running_mypy.html#how-imports-are-found> (which superseeds PEP 561):
4+
5+
> 1. [Stubs](https://typing.python.org/en/latest/spec/glossary.html#term-stub) or Python source manually put in the beginning of the path. Type checkers SHOULD provide this to allow the user complete control of which stubs to use, and to patch broken stubs or [inline](https://typing.python.org/en/latest/spec/glossary.html#term-inline) types from packages. In mypy the `$MYPYPATH` environment variable can be used for this.
6+
> 2. User code - the files the type checker is running on.
7+
> 3. Typeshed stubs for the standard library. These will usually be vendored by type checkers, but type checkers SHOULD provide an option for users to provide a path to a directory containing a custom or modified version of typeshed; if this option is provided, type checkers SHOULD use this as the canonical source for standard-library types in this step.
8+
> 4. **[Stub](https://typing.python.org/en/latest/spec/glossary.html#term-stub) packages - these packages SHOULD supersede any installed inline package. They can be found in directories named `foopkg-stubs` for package `foopkg`.**
9+
> 5. **Packages with a `py.typed` marker file - if there is nothing overriding the installed package, and it opts into type checking, the types bundled with the package SHOULD be used (be they in `.pyi` type stub files or inline in `.py` files).**
10+
> 6. If the type checker chooses to additionally vendor any third-party stubs (from typeshed or elsewhere), these SHOULD come last in the module resolution order.
11+
12+
Here, [NumPy](https://github.com/numpy/numpy)'s bundled stubs fall under 5., and [NumType](https://github.com/numpy/numtype/)'s [`numpy-stubs`](https://github.com/numpy/numtype/tree/2fb0af907b68558e4b0778c9dc4b21262105adb2/src/numpy-stubs) fall under 4..
13+
So NumType should be prioritized over the NumPy.
14+
15+
Pyright behavior confirms that this is indeed what should happen.
16+
17+
But mypy appears to incorrectly prioritize 5. (`numpy/__init__.pyi`) over 4. (`numpy-stubs/__init__.pyi` from NumType) &mdash;
18+
it should be the other way around.
19+
20+
## Env setup
21+
22+
Using python 3.10+ and [`uv`](https://docs.astral.sh/uv/)
23+
24+
```bash
25+
uv venv .venv
26+
source .venv/bin/activate
27+
```
28+
29+
If you don't have `uv` installed, then replace `uv` with `python -m`, and later on you can replace `uv pip` with `pip`.
30+
31+
### Install (without NumType)
32+
33+
Install `mypy 1.5.0`, `pyright 1.1.400`, and `numpy 2.2.5`:
34+
35+
```bash
36+
uv pip uninstall numtype
37+
uv pip install --reinstall -r requirements.txt
38+
```
39+
40+
(the `--reinstall` flag is only needed after the nuclear workaround)
41+
42+
To confirm:
43+
44+
```bash
45+
$ uv pip list
46+
Package Version
47+
----------------- -------
48+
mypy 1.15.0
49+
mypy-extensions 1.1.0
50+
nodeenv 1.9.1
51+
numpy 2.2.5
52+
pyright 1.1.400
53+
typing-extensions 4.13.2
54+
```
55+
56+
### Install (with NumType)
57+
58+
Install `mypy 1.5.0`, `pyright 1.1.400`, `numpy 2.2.5`, and `numtype @ 2fb0af9`
59+
60+
```bash
61+
uv pip install -r requirements-numtype.txt
62+
```
63+
64+
To confirm:
65+
66+
```bash
67+
$ uv pip list
68+
Package Version
69+
----------------- ------------
70+
mypy 1.15.0
71+
mypy-extensions 1.1.0
72+
nodeenv 1.9.1
73+
numpy 2.2.5
74+
numtype 2.2.5.0.dev0
75+
pyright 1.1.400
76+
typing-extensions 4.13.2
77+
```
78+
79+
## Bug demo
80+
81+
In NumPy's bundled stubs (`numpy==2.2.5`), the type of `np.True_` ([src](https://github.com/numpy/numpy/blob/7be8c1f9133516fe20fd076f9bdfe23d9f537874/numpy/__init__.pyi#L1161)) is called `numpy.bool` (shadowing `builtin.bool`).
82+
83+
In NumType's `numpy-stubs` (`2fb0af9`), the same `numpy.True_` is defined in [`numpy-stubs/_core/numeric.pyi`](https://github.com/numpy/numtype/blob/2fb0af907b68558e4b0778c9dc4b21262105adb2/src/numpy-stubs/_core/numeric.pyi#L623) (re-exported in [`__init__.pyi`](https://github.com/numpy/numtype/blob/2fb0af907b68558e4b0778c9dc4b21262105adb2/src/numpy-stubs/__init__.pyi#L77)), and its type is a `np.bool_` (note the trailing underscore).
84+
85+
So with a `reveal_type(np.True_)` (in the `main.pyi` of this repo) we'll be able to tell which stubs used.
86+
87+
### Pyright (without NumType)
88+
89+
NumType: No
90+
91+
```bash
92+
$ pyright .
93+
/home/joren/Workspace/mypy-numtype/main.pyi
94+
/home/joren/Workspace/mypy-numtype/main.pyi:5:17 - information: Type of "np.True_" is "bool[Literal[True]]"
95+
```
96+
97+
`numpy.bool` => NumPy's bundled stubs are used :white_check_mark:
98+
99+
### Pyright (with NumType)
100+
101+
```bash
102+
$ pyright .
103+
/home/joren/Workspace/mypy-numtype/main.pyi
104+
/home/joren/Workspace/mypy-numtype/main.pyi:3:13 - information: Type of "np.True_" is "bool_[Literal[True]]"
105+
```
106+
107+
`numpy.bool_` => NumType's `numpy-stubs` are used :white_check_mark:
108+
109+
---
110+
111+
### Mypy (without NumType)
112+
113+
NumType: No
114+
115+
```bash
116+
$ rm -rf .mypy_cache
117+
$ mypy .
118+
main.pyi:3: note: Revealed type is "numpy.bool[Literal[True]]"
119+
Success: no issues found in 1 source file
120+
```
121+
122+
`numpy.bool` => NumPy's bundled stubs are used :white_check_mark:
123+
124+
### Mypy (with NumType)
125+
126+
```bash
127+
$ rm -rf .mypy_cache
128+
$ mypy main.pyi
129+
main.pyi:3: note: Revealed type is "numpy.bool[Literal[True]]"
130+
```
131+
132+
`numpy.bool` => NumPy's bundled stubs are used :x:
133+
134+
## The nuclear workaround
135+
136+
<details>
137+
<summary>The only workaround I was able to find (after several full days of trying), was to remove all <code>.pyi</code> from numpy's local installation directory. But this is not something I can realistically ask the users of NumPy to do.</summary>
138+
139+
First do a dry run:
140+
141+
```bash
142+
$ find ./.venv/**/site-packages/numpy -name "*.pyi" -type f
143+
./.venv/lib/python3.13/site-packages/numpy/matlib.pyi
144+
./.venv/lib/python3.13/site-packages/numpy/fft/_helper.pyi
145+
./.venv/lib/python3.13/site-packages/numpy/fft/_pocketfft.pyi
146+
[...]
147+
```
148+
149+
If all is good, press the red button:
150+
151+
```bash
152+
$ find ./.venv/**/site-packages/numpy -name "*.pyi" -type f -delete
153+
```
154+
155+
Re-run pyright:
156+
157+
```bash
158+
$ pyright .
159+
/home/joren/Workspace/mypy-numtype/main.pyi
160+
/home/joren/Workspace/mypy-numtype/main.pyi:3:13 - information: Type of "np.True_" is "bool_[Literal[True]]"
161+
```
162+
163+
Good; that's exactly the same result as before (with NumType).
164+
165+
Now run mypy again:
166+
167+
```bash
168+
$ rm -rf .mypy_cache
169+
$ mypy .
170+
main.pyi:3: note: Revealed type is "numpy.bool_[Literal[True]]"
171+
Success: no issues found in 1 source file
172+
```
173+
174+
This is indeed the correct output, which for the 2nd time demonstrates that mypy does not comply with PEP 561.
175+
</details>

main.pyi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import numpy as np
2+
3+
reveal_type(np.True_)

requirements-numtype.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-r requirements.txt
2+
3+
numtype @ git+https://github.com/numpy/numtype.git@2fb0af9

requirements.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
numpy==2.2.5
2+
3+
mypy==1.15.0
4+
pyright==1.1.400

0 commit comments

Comments
 (0)