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.
