mypy Setup and Configuration: Step-by-Step
mypy is a static type checker for Python that reads your type hints and validates your code without running it. Getting mypy up and running takes just a few minutes: install it via pip, configure a mypy.ini file, and run it against your codebase. This article walks you through setup from zero to your first successful type check.
Installing mypy with pip
mypy is available on PyPI and installs like any standard Python package. First, verify you have Python 3.6+ installed:
python --version
# Output: Python 3.x.x
Then install mypy using pip:
pip install mypy
To verify the installation, check the version:
mypy --version
# Output: mypy X.Y.Z (compiled: yes)
If you're working in a virtual environment (recommended), activate it first, then run the pip install. This ensures mypy is isolated to your project:
# Create a virtual environment
python -m venv venv
# Activate it (on Windows)
venv\Scripts\activate
# On macOS/Linux
source venv/bin/activate
# Then install mypy
pip install mypy
Running mypy on a Python File
Once installed, mypy can check any .py file. Create a simple test file to verify setup:
# hello.py
def greet(name: str) -> str:
return f"Hello, {name}!"
message: str = greet("Alice")
print(message)
# This line will trigger a mypy error:
bad_message: str = greet(42) # Error: int passed where str expected
Run mypy against this file:
mypy hello.py
If mypy is properly installed, it will output:
hello.py:7: error: Argument 1 to "greet" has incompatible type "int"; expected "str"
This error message is the core of mypy's value: it caught a type mismatch without running the file. If you ran the file itself, Python would allow it (until greet tried to use the int in a string operation). mypy caught it earlier.
Creating a mypy.ini Configuration File
For larger projects, create a mypy.ini file in your project root to control mypy's behavior. This file specifies which directories to check, which to ignore, and what strictness level to enforce.
Here's a minimal mypy.ini for a typical project:
[mypy]
# Python version to target
python_version = 3.10
# Directory to check (usually your main source directory)
mypy_path = src
# Show error codes
show_error_codes = True
# Enforce strict mode (catches more issues)
strict = True
# Directories to ignore
ignore_patterns = tests/, build/, dist/
With this configuration, run mypy from your project root without specifying a file:
mypy
mypy will now check all .py files in the src/ directory, respect the python_version setting, and use strict mode.
Key Configuration Options Explained
python_version — Set to your target Python version. mypy uses this to determine which language features are available. For Python 3.10, use 3.10.
strict — Set strict = True to enable the strictest checking. This enforces:
- All functions must have explicit return type annotations
- All function parameters must be annotated (except
selfandcls) - Implicit
Anytypes are forbidden - No untyped
defstatements allowed
For gradual type checking (adding hints incrementally), leave strict = False and enable individual strict options:
[mypy]
python_version = 3.10
check_untyped_defs = True
disallow_untyped_defs = True
warn_unused_ignores = True
warn_return_any — If a function can return Any, mypy warns about it. Useful for catching implicit Any leakage.
disallow_incomplete_defs — Forbid functions with partial type annotations (some parameters typed, some not).
exclude — A regex pattern of directories to skip. Example: exclude = ^(tests|build)/. This is an alternative to ignore_patterns.
Ignoring Specific Lines and Files
Sometimes you need to tell mypy to skip a particular line (e.g., for third-party libraries without type stubs). Use the # type: ignore comment:
import some_untyped_library # type: ignore
result = some_untyped_library.do_something() # Type is Any, mypy won't complain
To ignore an entire file, add a # mypy: ignore-errors comment at the top:
# mypy: ignore-errors
# This file has no type hints and mypy won't check it
def untyped_function(x):
return x * 2
A Complete Project Structure Example
Here's what a real project layout with mypy might look like:
myproject/
├── mypy.ini
├── setup.py
├── src/
│ ├── __init__.py
│ ├── main.py
│ └── utils.py
├── tests/
│ ├── test_main.py
│ └── test_utils.py
└── venv/
Sample mypy.ini:
[mypy]
python_version = 3.10
mypy_path = src
strict = True
show_error_codes = True
# Exclude test and build directories
[mypy-tests.*]
ignore_errors = True
[mypy-setup]
ignore_errors = True
Sample src/main.py:
def add(a: int, b: int) -> int:
"""Add two integers and return the result."""
return a + b
def main() -> None:
"""Entry point."""
result: int = add(5, 3)
print(f"5 + 3 = {result}")
if __name__ == "__main__":
main()
Run mypy:
mypy
# Success: no issues found in src/
Integrating mypy into Your Development Workflow
In your IDE: Most editors (VS Code, PyCharm, Sublime) offer mypy extensions. Install the Python extension for your editor and configure it to use mypy as the default type checker.
In pre-commit hooks: Automatically run mypy before each commit:
pip install pre-commit
Create a .pre-commit-config.yaml in your project root:
repos:
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
hooks:
- id: mypy
args: [--strict]
Then run:
pre-commit install
Now mypy runs automatically before each commit, ensuring no type errors slip in.
In CI/CD: Add mypy to your GitHub Actions, GitLab CI, or similar:
# .github/workflows/type-check.yml
name: Type Check
on: [push, pull_request]
jobs:
mypy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- run: pip install mypy
- run: mypy src/
Common Installation Issues and Fixes
Issue: mypy: command not found
Solution: Verify mypy is installed in the active Python environment. Run pip install mypy again or check that your virtual environment is activated.
Issue: error: PYTHONPATH not set; cannot find source files
Solution: Add mypy_path to your mypy.ini, pointing to your source directory (usually src/).
Issue: mypy ignores your configuration file
Solution: Ensure mypy.ini is in your project root (the directory where you run mypy). mypy searches for the config file starting from the current directory and moving upward.
Key Takeaways
- Install mypy with
pip install mypyand verify withmypy --version - Run mypy on a file or directory:
mypy hello.pyormypy src/ - Create a
mypy.iniconfiguration file in your project root to set Python version, source paths, and strictness levels - Use
strict = Truefor maximum type safety; disable it and enable individual options for gradual typing - Ignore specific lines with
# type: ignorecomments or entire files with# mypy: ignore-errors - Integrate mypy into pre-commit hooks, CI/CD pipelines, and your IDE for continuous type checking
Frequently Asked Questions
Do I have to use mypy.ini, or can I pass arguments on the command line?
You can do both. Command-line arguments override mypy.ini settings. For most projects, a config file is cleaner: mypy.ini lives in your repo and applies to all developers, whereas command-line args must be remembered and re-entered.
What's the difference between check_untyped_defs and disallow_untyped_defs?
check_untyped_defs analyzes function bodies but allows untyped parameters. disallow_untyped_defs forbids any function without full type annotations. The latter is stricter and enforces explicit typing.
Can I use mypy with Python 2?
mypy supports Python 2 syntax checking with some limitations. However, Python 2 reached end-of-life in 2020. Use Python 3.6+ for best mypy support.
Should I enable strict mode right away on an existing codebase?
No. Gradual typing is better. Start with strict = False, enable show_error_codes = True, and incrementally add hints to the most critical modules. Once the codebase is mostly typed, enable strict = True.
How do I exclude a third-party library that has no type stubs?
Add it to a [mypy-<package>] section in mypy.ini: [mypy-some_library] ignore_missing_imports = True.
Further Reading
- mypy Official Documentation — Complete reference for all mypy options and features
- mypy Cheat Sheet — Quick reference for type hints and config options
- Incremental Typing PEP 484 Supplement — Guide to gradual type adoption
- Python Typing Best Practices — Official recommendations from the Python docs