Note
This has been fixed in python/mypy#19001
From https://typing.python.org/en/latest/spec/distributing.html#import-resolution-ordering (which superseeds PEP 561):
- Stubs 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 types from packages. In mypy the
$MYPYPATH
environment variable can be used for this.- User code - the files the type checker is running on.
- 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.
- Stub packages - these packages SHOULD supersede any installed inline package. They can be found in directories named
foopkg-stubs
for packagefoopkg
.- 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).- 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.
Here, NumPy's bundled stubs fall under 5., and NumType's numpy-stubs
fall under 4..
So NumType should be prioritized over the NumPy.
Pyright behavior confirms that this is indeed what should happen.
But mypy appears to incorrectly prioritize 5. (numpy/__init__.pyi
) over 4. (numpy-stubs/__init__.pyi
from NumType) —
it should be the other way around.
Using python 3.10+ and uv
uv venv .venv
source .venv/bin/activate
If you don't have uv
installed, then replace uv
with python -m
, and later on you can replace uv pip
with pip
.
Install mypy 1.5.0
, pyright 1.1.400
, and numpy 2.2.5
:
uv pip uninstall numtype
uv pip install --reinstall -r requirements.txt
(the --reinstall
flag is only needed after the nuclear workaround)
To confirm:
$ uv pip list
Package Version
----------------- -------
mypy 1.15.0
mypy-extensions 1.1.0
nodeenv 1.9.1
numpy 2.2.5
pyright 1.1.400
typing-extensions 4.13.2
Install mypy 1.5.0
, pyright 1.1.400
, numpy 2.2.5
, and numtype @ 2fb0af9
uv pip install -r requirements-numtype.txt
To confirm:
$ uv pip list
Package Version
----------------- ------------
mypy 1.15.0
mypy-extensions 1.1.0
nodeenv 1.9.1
numpy 2.2.5
numtype 2.2.5.0.dev0
pyright 1.1.400
typing-extensions 4.13.2
In NumPy's bundled stubs (numpy==2.2.5
), the type of np.True_
(src) is called numpy.bool
(shadowing builtin.bool
).
In NumType's numpy-stubs
(2fb0af9
), the same numpy.True_
is defined in numpy-stubs/_core/numeric.pyi
(re-exported in __init__.pyi
), and its type is a np.bool_
(note the trailing underscore).
So with a reveal_type(np.True_)
(in the main.pyi
of this repo) we'll be able to tell which stubs used.
NumType: No
$ pyright .
/home/joren/Workspace/mypy-numtype/main.pyi
/home/joren/Workspace/mypy-numtype/main.pyi:5:17 - information: Type of "np.True_" is "bool[Literal[True]]"
numpy.bool
=> NumPy's bundled stubs are used ✅
$ pyright .
/home/joren/Workspace/mypy-numtype/main.pyi
/home/joren/Workspace/mypy-numtype/main.pyi:3:13 - information: Type of "np.True_" is "bool_[Literal[True]]"
numpy.bool_
=> NumType's numpy-stubs
are used ✅
NumType: No
$ rm -rf .mypy_cache
$ mypy .
main.pyi:3: note: Revealed type is "numpy.bool[Literal[True]]"
numpy.bool
=> NumPy's bundled stubs are used ✅
$ rm -rf .mypy_cache
$ mypy main.pyi
main.pyi:3: note: Revealed type is "numpy.bool[Literal[True]]"
numpy.bool
=> NumPy's bundled stubs are used ❌
Install the PR branch with the fix (python/mypy#19001):
uv pip install "git+https://github.com/jorenham/mypy@fix-18997"
$ rm -rf .mypy_cache
$ mypy main.pyi
main.pyi:3: note: Revealed type is "numpy.bool_[Literal[True]]"
numpy.bool_
=> NumType's numpy-stubs
are used ✅
The only workaround I was able to find (after several full days of trying), was to remove all .pyi
from numpy's local installation directory. But this is not something I can realistically ask the users of NumPy to do.
First do a dry run:
$ find ./.venv/**/site-packages/numpy -name "*.pyi" -type f
./.venv/lib/python3.13/site-packages/numpy/matlib.pyi
./.venv/lib/python3.13/site-packages/numpy/fft/_helper.pyi
./.venv/lib/python3.13/site-packages/numpy/fft/_pocketfft.pyi
[...]
If all is good, press the red button:
$ find ./.venv/**/site-packages/numpy -name "*.pyi" -type f -delete
Re-run pyright:
$ pyright .
/home/joren/Workspace/mypy-numtype/main.pyi
/home/joren/Workspace/mypy-numtype/main.pyi:3:13 - information: Type of "np.True_" is "bool_[Literal[True]]"
Good; that's exactly the same result as before (with NumType).
Now run mypy again:
$ rm -rf .mypy_cache
$ mypy .
main.pyi:3: note: Revealed type is "numpy.bool_[Literal[True]]"
Success: no issues found in 1 source file
This is indeed the correct output, which for the 2nd time demonstrates that mypy does not comply with PEP 561.