How to configure mypy strict mode
mypy skips completely unannotated function bodies by default. Strict mode requires annotations and enables optional checks, including checking those bodies. It still permits some uses of Any; the exact flag bundle is defined by the installed mypy release.
Enable strict mode
Add this to pyproject.toml:
[tool.mypy]
strict = trueRun the checker:
uv run mypy src/uv run executes the command inside the project’s virtual environment, ensuring all dependencies are installed first. A clean run prints Success: no issues found ... and exits 0; type errors exit 1.
For a one-off check, uv run mypy --strict src/ applies the same strict preset. Keep persistent policy in the configuration used by both CI and editors.
Inspect the strict checks
Run uv run mypy --help to see the installed release’s --strict expansion. Its core checks include:
| Setting | Check |
|---|---|
disallow_untyped_defs / disallow_incomplete_defs |
Missing or incomplete function annotations |
disallow_untyped_calls |
Calls from typed code to unannotated functions |
check_untyped_defs |
Known operations inside unannotated function bodies |
disallow_untyped_decorators |
Untyped decorators applied to typed functions |
disallow_any_generics / disallow_subclassing_any |
Missing generic parameters and subclassing Any |
warn_return_any / warn_redundant_casts / warn_unused_ignores |
Returning Any, redundant casts, and stale ignores |
no_implicit_reexport / strict_equality / extra_checks |
Implicit exports, non-overlapping comparisons, and additional checks |
This list describes the preset’s main checks. warn_unreachable and warn_unused_configs require separate settings. Strict bytes behavior is a default rather than an extra check supplied by strict.
A function’s unannotated parameters remain Any during body checking, so check_untyped_defs alone does not provide the same protection as annotated parameters.
Require annotations in selected modules
For an existing project, check bodies globally and enable individual checks in modules that are ready:
[tool.mypy]
check_untyped_defs = true
[[tool.mypy.overrides]]
module = ["mypackage.api", "mypackage.api.*"]
disallow_untyped_defs = true
disallow_incomplete_defs = true
disallow_untyped_calls = true
warn_return_any = trueInclude both a package’s name and its submodule pattern. These flags require annotations, reject untyped calls from typed code, and reject returning Any from typed functions. Keep strict = true in the global table: putting it inside an override can enable the strict bundle outside the selected modules. See the gradual adoption recipe.
For a project that is almost ready, start strict and disable individual settings deliberately:
[tool.mypy]
strict = true
warn_return_any = falseHandle dependencies without annotations
Missing-import diagnostics also occur outside strict mode. Install available stub packages before adding an exception:
uv add --dev types-requests types-PyYAMLuv records the stub packages as development dependencies and updates uv.lock. Check that the stub versions match the project’s runtime libraries.
If no usable annotations or stubs exist, suppress only the intended package:
[[tool.mypy.overrides]]
module = ["some_untyped_library", "some_untyped_library.*"]
ignore_missing_imports = trueImported values may then become Any, reducing checks on calls into that dependency. Keep the exception narrow instead of setting ignore_missing_imports globally.
Keep suppression and CI behavior explicit
Use # type: ignore[error-code] on the line that mypy reports. With warn_unused_ignores enabled by strict mode, stale ignores become errors too. Options with warn_ names still produce failing mypy diagnostics; they are not advisory CI warnings.
Keep the same project configuration and lockfile in CI. Invalid command usage or a fatal checking problem can exit 2, distinct from the 1 used for ordinary type errors.