How mypy reads Python annotations, and where its checks stop
Optional static typing for Python
At a glance
- What is it?
- Mypy reads the PEP 484 hints you add to a Python program and reports type errors without executing it. It is exact where you annotated, blind where you did not, and its errors never stop the interpreter.
- Who is it for?
- Adopt mypy if your team already writes annotations and can live with the Python 3.10 interpreter floor; skip it if the codebase has no hints yet, because mypy only inspects the statically typed parts of a program. Before wiring it into CI, run `mypy PROGRAM` over a single package and see how much of the output is real signal, since that decides whether daemon mode matters.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.
Star history
- python/mypy20,722 ★ · +76
| Repository | 2026-09-21 | 2026-11-13 |
|---|---|---|
| python/mypy | 20.6k | 20.7k |
76 Stars in the last 53 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Static checking: mypy never runs your code
Mypy is a static type checker: it reads the hints you wrote under PEP 484 and reports the places where a value of one type is used as another. No part of your program is executed, so checking a large module costs parsing and analysis rather than a run.
The project's own example is a mistake that never gets the chance to happen at runtime. `input()` hands back a string, and adding an integer to it is reported before an interpreter would evaluate the line:
number = input("What is your favourite number?")
print("It is", number + 1) # error: Unsupported operand types for + ("str" and "int")That message shows the mechanism in one line. The type of `number` is known without any annotation on your side, because `input` is a known builtin, and the right operand is an int literal, so the mismatch is a fact rather than a guess. Behind that sit type inference, generics, callable types, tuple types, union types and structural subtyping. Gradual typing means you can annotate one function at a time and leave everything else dynamic, which is the design decision that makes adoption possible and also the one that limits what you get.
Three install routes, and an interpreter floor of Python 3.10
PyPI is the ordinary route:
python3 -m pip install -U mypyTo run whatever is on the tip of the repository instead:
python3 -m pip install -U git+https://github.com/python/mypy.gitThe interpreter floor is enforced in code. setup.py writes `ERROR: You need Python 3.10 or later to use mypy.` to stderr and exits before it imports anything else, so a team pinned to an older interpreter cannot install through any of these routes. The classifiers in pyproject.toml include Python 3.10, 3.11 and 3.12.
A first check takes one argument:
mypy PROGRAMMypy inspects only the statically typed parts of a program, so on a partly annotated codebase the output itself is the first thing worth reading, not the exit status. The program still runs the same way whether or not mypy had anything to say about it:
python3 PROGRAMThere is also a browser shortcut. The project points at an online playground at mypy-play.net, developed by Yusuke Miyazaki, for trying the checker before committing to a dependency.
Unannotated code and third party dependencies are what mypy cannot see
Gradual typing is mypy's central concession and also its main blind spot. An unannotated function is treated as dynamic, so a hint on one function tells you nothing about the body of the next one. Mypy checks the code you annotated and leaves the rest to the interpreter.
The pre-commit integration names the cost in the project's own words: using pre-commit mirrors-mypy comes with the note that, by default, it will limit mypy's ability to analyse your third party dependencies. Concretely, a fresh checkout where you add a hundred hints reports errors concentrated in the files you touched, while a type error three calls away in an unannotated helper stays invisible until that helper is annotated. The consequence for the reader is that mypy's output measures your annotations, not your program's correctness, and a clean run over an unannotated codebase says close to nothing.
Triage is split too. General questions about Python typing go to the typing discussions and gitter chat, new type system features go to discuss.python.org, and a report about a specific library or function is asked for at the typeshed tracker instead of the mypy issue tracker. Two repositories, two queues, one problem.
dmypy keeps a long lived process between runs
On a large code base the one-shot command is the wrong shape, and mypy ships a daemon for that case:
dmypy run -- PROGRAMThe claim attached to it is speed: much faster, often sub-second, incremental updates, because the process stays warm and reuses what it already knows about the files you did not touch. That is a different operating model from `mypy PROGRAM`, which starts from scratch each time and discards what it learned.
The README does not say how to stop a daemon or how to throw its state away, and a long lived process holding a stale view of your source is a failure mode you have to read the daemon documentation to resolve. The trade is a background process with its own lifecycle, managed outside the editor, in exchange for update times on a repository where a cold run is measured in seconds. On a small package the one-shot command stays the simpler choice.
The PyPI wheel is mypyc compiled, about 4 times faster than interpreted
Mypyc is a separate project that uses the same type hints to compile Python modules into C extensions, and mypy is built with it. The project's claim for that arrangement is specific: it makes mypy approximately 4 times faster than it would be if interpreted.
You can check the claim from the other side, because the interpreted build is one flag away:
python3 -m pip install --no-binary mypy -U mypyThe trade-off follows from what you installed it for. If you are type checking your own project, the compiled wheel is what you want and nothing about your workflow changes. If you intend to read or step through mypy's own implementation, the interpreted build is the one you ask for, and the factor goes with it. Development builds compiled with mypyc are published separately, as wheels on the mypyc releases page, so a compiled release and a compiled development build are two different downloads with two different upgrade paths.
Library signatures come from typeshed, a different repository
Signatures for libraries you do not own do not live in this repository's code. When a report concerns a specific library or function, the project asks for it at the typeshed tracker, a separate repository, and points at the issue tracker of the library itself otherwise. The vendored copy surfaces in pyproject.toml, where license-files names both `LICENSE` and `mypy/typeshed/LICENSE`.
For a reader this splits responsibility in a way that matters during upgrades. Where a signature comes from the bundled typeshed, one that is wrong for the version of a library you actually have installed keeps being reported until typeshed changes, and a corrected stub is a contribution to another project rather than a patch you can carry inside your own tree. The project's own routing reflects that: a common issues page first, the mypy issue tracker second, typeshed for anything library specific.
Mypy reports errors, it does not block: enforcement lives in CI
Two facts decide how much of mypy you really get. First, hints do not change execution. The project describes them as similar to comments and states that you can always run your statically typed program with the interpreter even when mypy is reporting errors, so nothing in the checker prevents a bad call from reaching production.
Second, the README does not document a configuration file, per module exclusions, or a way to silence a single line, although it links a list of error codes and a common issues page in the documentation. Enforcement is something you build around the command: run `mypy PROGRAM` inside your build and decide for yourself what counts as a failure, because the configuration surface is defined by the shipped documentation rather than by the checker.
The consequence is that adding mypy to a repository changes what runs in CI before it changes what runs in production. Nothing about interpreter behaviour moves, and the first report you read is a report about your annotations, including the ones that were wrong about a library stub.
MIT licensed, shipped through PyPI, with no GitHub releases
Mypy is MIT licensed, with `LICENSE` and the vendored `mypy/typeshed/LICENSE` declared in pyproject.toml, and the author field names Jukka Lehtosalo. Versioning does not run through GitHub releases, because the repository publishes none. The changelog lives in `CHANGELOG.md` at the root and on the mypy-lang.blogspot.com site, and the package is versioned on PyPI, which makes your lock file the record of what you actually run.
The last push to master was on 2026-11-02, and the repository is not archived, so the movement is current rather than historical. It reaches your dependency pins, because the build requirements are written against interpreter version: `typing_extensions>=4.6.0` for `python_version<'3.15'` and `>=4.16.0` from 3.15 onwards, `mypy_extensions>=1.0.0`, `pathspec>=1.0.0`, and `tomli>=1.1.0` only where `python_version<'3.11'`. Moving to a new Python can move a floor you had pinned.
Mypy is also type checked by itself. mypy_self_check.ini and mypy_bootstrap.ini sit at the root, and a comment in pyproject.toml explains that the build requirements must stay in sync with mypy-requirements.txt and build-requirements.txt because both are needed for self-typechecking. That is the standard the project holds itself to, and it explains why a fully annotated codebase is the normal case upstream rather than an opt in.
Editorial conclusion
Adopt mypy if your team already writes annotations and can live with the Python 3.10 interpreter floor; skip it if the codebase has no hints yet, because mypy only inspects the statically typed parts of a program. Before wiring it into CI, run `mypy PROGRAM` over a single package and see how much of the output is real signal, since that decides whether daemon mode matters. The last push was on 2026-11-02 and the project publishes no GitHub releases, so read CHANGELOG.md and pin the PyPI version when you upgrade.
Frequently asked questions
What does mypy do in Python?
It reads the type hints you add under PEP 484 and reports when a value is used as the wrong type, without executing the program. The example in the README flags `number + 1` when `number` came back from `input()`.
Should I use mypy or Pyright?
The README makes no comparison with any other checker, so the project itself gives you nothing to weigh the two against. Its badges link to psf/black and astral-sh/ruff, and sends type system design questions to discuss.python.org.
How do I use mypy in Python?
Install it with `python3 -m pip install -U mypy`, then point it at a program with `mypy PROGRAM`. For a large code base, the daemon form `dmypy run -- PROGRAM` gives much faster, often sub-second, incremental updates.
How does mypy work with VS Code?
VS Code provides basic integration with mypy. Vim uses `let g:syntastic_python_checkers=['mypy']` in `~/.vimrc` for Syntastic, while ALE should be enabled by default once mypy is installed or can be enabled with `let b:ale_linters = ['mypy']` in `~/vim/ftplugin/python.vim`. Flycheck, SublimeLinter-contrib-mypy, a PyCharm plugin and idlemypyextension cover Emacs, Sublime Text, PyCharm and IDLE.
What is the difference between Python typing and mypy?
Typing is the annotation syntax, mypy is the checker that reads it. Mypy supports type inference, generics, callable types, tuple types, union types and structural subtyping, and its gradual design lets you annotate a codebase slowly and fall back to dynamic typing when static typing is not convenient.
What is better than mypy?
The project names no replacement and makes no ranking claim. For general typing questions it sends you to the python/typing discussions and gitter chat, and for a library mypy misreports it points at the typeshed tracker, which is a separate repository.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/python-mypy)Star history chart for your README
[](https://hysenlabs.com/projects/python-mypy)Was this useful?