What is Mypy, How to Use It, and Why It Matters
Python is known for being a dynamically typed language — you don’t have to declare variable types, and everything works at runtime. But as your codebase grows, undetected type errors can creep in. That’s where Mypy comes in.
Mypy is a static type checker for Python. It checks your Python code for type errors without running it.
Why Use Mypy?
- ✅ Detect bugs early (before running the code)
- ✅ Improve code quality and readability
- ✅ Easier refactoring and debugging
- ✅ Helps IDEs with better autocomplete and hints
- ✅ Integrates smoothly into CI/CD workflows
You might’ve seen Mypy mentioned in our Shift Left Paradigm article, where it plays a key role in early-stage static analysis.
Installing Mypy
pip install mypy
First Example: Catching a Type Error
def greet(name: str) -> str:
return "Hello " + name
print(greet(42)) # 😬 Works at runtime but wrong type!
Run Mypy:
mypy script.py
Mypy will warn you:
error: Argument 1 to "greet" has incompatible type "int"; expected "str"
Example: Catching Missing Return Types
def add(x: int, y: int):
return x + y
Mypy can infer the return type but warns you if you’ve set strict rules for missing annotations. It encourages explicit typing:
def add(x: int, y: int) -> int:
return x + y
Advanced Typing: Union, Optional, List
from typing import Union, Optional, List
def get_price(code: Union[str, int]) -> Optional[float]:
if isinstance(code, str):
return 9.99
return None
Mypy handles all of this. If you accidentally do:
price: float = get_price("A123")
It will warn:
error: Incompatible types in assignment (expression has type "Optional[float]", variable has type "float")
Using Mypy with Classes
class User:
def __init__(self, id: int, name: str) -> None:
self.id = id
self.name = name
def get_username(user: User) -> str:
return user.name
This ensures that you never accidentally pass a dictionary instead of a User
instance.
How Mypy Helps Refactoring
If you refactor a large project and rename a class or function signature, Mypy will catch all related type mismatches before you even run the tests.
Strict Mode: Safer, Cleaner Code
Enable strict mode in mypy.ini
or pyproject.toml
:
[mypy]
strict = True
disallow_untyped_defs = True
warn_unused_ignores = True
Integration with CI/CD
You can add Mypy to your GitHub Actions or GitLab CI pipeline to automatically reject PRs with type errors.
Combining Mypy with Tools like pyright
and ruff
pyright
: A faster alternative with better TypeScript-like checkingruff
: A linter that complements Mypy for overall code style enforcement
Limitations of Mypy
- Runtime behavior still rules — Mypy only helps pre-runtime
- Some dynamic Python tricks (e.g., monkey patching) may confuse Mypy
- You must annotate — which may feel verbose for very small scripts
Conclusion
Mypy is a powerful tool that helps Python developers shift left — detecting bugs before they ship. It enforces clean design, improves developer experience, and is a must-have in any professional Python codebase.