mypy
mypy - Static type checker for Python with gradual typing, strict mode, Protocol support, and framework integration
What this skill does
# mypy - Static Type Checking for Python
## Overview
mypy is the standard static type checker for Python, enabling gradual typing with type hints (PEP 484) and comprehensive type safety. It catches type errors before runtime, improves code documentation, and enhances IDE support while maintaining Python's dynamic nature through incremental adoption.
**Key Features**:
- Gradual typing: Add types incrementally to existing code
- Strict mode: Maximum type safety with --strict flag
- Type inference: Automatically infer types from context
- Protocol support: Structural typing (duck typing with types)
- Generic types: TypeVar, Generic, and advanced type patterns
- Framework integration: FastAPI, Django, Pydantic compatibility
- Plugin system: Extend type checking for libraries
- Incremental checking: Fast type checking on large codebases
**Installation**:
```bash
# Basic mypy
pip install mypy
# With common type stubs
pip install mypy types-requests types-PyYAML types-redis
# For FastAPI projects
pip install mypy pydantic
# For Django projects
pip install mypy django-stubs
# Development setup
pip install mypy pre-commit
```
## Type Annotation Basics
### 1. Variable Type Hints
```python
# Basic types
name: str = "Alice"
age: int = 30
height: float = 5.9
is_active: bool = True
# Type inference (mypy infers types)
count = 10 # mypy infers: int
message = "Hello" # mypy infers: str
# Multiple types with Union
from typing import Union
user_id: Union[int, str] = 123 # Can be int OR str
result: Union[int, None] = None # Nullable int
# Optional (shorthand for Union[T, None])
from typing import Optional
user_email: Optional[str] = None # Can be str or None
```
### 2. Function Type Hints
```python
# Basic function typing
def greet(name: str) -> str:
return f"Hello, {name}"
# Multiple parameters
def add(a: int, b: int) -> int:
return a + b
# Optional parameters with defaults
def create_user(name: str, age: int = 18) -> dict:
return {"name": name, "age": age}
# No return value
def log_message(message: str) -> None:
print(message)
# Functions that never return
from typing import NoReturn
def raise_error() -> NoReturn:
raise ValueError("Always raises")
```
### 3. Collection Type Hints
```python
from typing import List, Dict, Set, Tuple
# List with element type
numbers: List[int] = [1, 2, 3, 4]
names: List[str] = ["Alice", "Bob", "Charlie"]
# Dict with key and value types
user_ages: Dict[str, int] = {"Alice": 30, "Bob": 25}
config: Dict[str, Union[str, int]] = {"host": "localhost", "port": 8000}
# Set with element type
unique_ids: Set[int] = {1, 2, 3}
# Tuple with fixed types
coordinate: Tuple[float, float] = (10.5, 20.3)
user_record: Tuple[int, str, bool] = (1, "Alice", True)
# Variable-length tuple
numbers: Tuple[int, ...] = (1, 2, 3, 4, 5)
# Modern syntax (Python 3.9+)
numbers: list[int] = [1, 2, 3]
user_ages: dict[str, int] = {"Alice": 30}
```
### 4. Class Type Hints
```python
class User:
# Class attributes
name: str
age: int
email: Optional[str]
def __init__(self, name: str, age: int, email: Optional[str] = None) -> None:
self.name = name
self.age = age
self.email = email
def get_info(self) -> Dict[str, Union[str, int]]:
return {
"name": self.name,
"age": self.age,
"email": self.email or "N/A"
}
@classmethod
def from_dict(cls, data: Dict[str, any]) -> "User":
return cls(
name=data["name"],
age=data["age"],
email=data.get("email")
)
```
## Advanced Type Hints
### 1. Literal Types
```python
from typing import Literal
# Restrict to specific values
def set_log_level(level: Literal["debug", "info", "warning", "error"]) -> None:
print(f"Log level: {level}")
# Valid
set_log_level("debug")
set_log_level("error")
# Type error: Argument 1 has incompatible type "verbose"
set_log_level("verbose")
# Multiple literals
Status = Literal["pending", "approved", "rejected"]
def update_status(status: Status) -> None:
pass
```
### 2. Type Aliases
```python
from typing import Dict, List, Union
# Simple alias
UserId = int
UserName = str
def get_user(user_id: UserId) -> UserName:
return f"User {user_id}"
# Complex aliases
JSON = Union[Dict[str, "JSON"], List["JSON"], str, int, float, bool, None]
Headers = Dict[str, str]
QueryParams = Dict[str, Union[str, int, List[str]]]
def make_request(
url: str,
headers: Headers,
params: QueryParams
) -> JSON:
pass
# NewType for distinct types
from typing import NewType
UserId = NewType("UserId", int)
ProductId = NewType("ProductId", int)
def get_user(user_id: UserId) -> str:
return f"User {user_id}"
user = UserId(123) # Valid
product = ProductId(456)
get_user(user) # Valid
get_user(product) # Type error: ProductId not compatible with UserId
```
### 3. Generics and TypeVar
```python
from typing import TypeVar, Generic, List
# TypeVar for generic functions
T = TypeVar("T")
def first_element(items: List[T]) -> T:
return items[0]
# Type inference
num = first_element([1, 2, 3]) # mypy infers: int
name = first_element(["Alice", "Bob"]) # mypy infers: str
# Bounded TypeVar
from typing import Union
NumericType = TypeVar("NumericType", int, float)
def add_numbers(a: NumericType, b: NumericType) -> NumericType:
return a + b
# Generic classes
class Stack(Generic[T]):
def __init__(self) -> None:
self._items: List[T] = []
def push(self, item: T) -> None:
self._items.append(item)
def pop(self) -> T:
return self._items.pop()
def is_empty(self) -> bool:
return len(self._items) == 0
# Usage with type inference
int_stack: Stack[int] = Stack()
int_stack.push(42)
int_stack.push("hello") # Type error: Expected int, got str
str_stack: Stack[str] = Stack()
str_stack.push("hello") # Valid
```
### 4. Protocol (Structural Typing)
```python
from typing import Protocol
# Define protocol (interface)
class Drawable(Protocol):
def draw(self) -> str:
...
# Any class with draw() method matches
class Circle:
def draw(self) -> str:
return "Drawing circle"
class Square:
def draw(self) -> str:
return "Drawing square"
# Function accepts any Drawable
def render(obj: Drawable) -> str:
return obj.draw()
# Both work (duck typing with types)
circle = Circle()
square = Square()
render(circle) # Valid
render(square) # Valid
# Runtime checkable protocols
from typing import runtime_checkable
@runtime_checkable
class Closeable(Protocol):
def close(self) -> None:
...
class File:
def close(self) -> None:
pass
# Runtime check
f = File()
isinstance(f, Closeable) # True
```
### 5. Callable Types
```python
from typing import Callable
# Function that takes another function
def apply_twice(func: Callable[[int], int], value: int) -> int:
return func(func(value))
def double(x: int) -> int:
return x * 2
result = apply_twice(double, 5) # Returns 20
# Generic callable
from typing import TypeVar
T = TypeVar("T")
R = TypeVar("R")
def map_values(
func: Callable[[T], R],
values: List[T]
) -> List[R]:
return [func(v) for v in values]
# Callable with multiple arguments
Validator = Callable[[str, int], bool]
def validate_user(name: str, age: int) -> bool:
return len(name) > 0 and age >= 0
validator: Validator = validate_user
```
## mypy Configuration
### 1. mypy.ini Configuration
```ini
# mypy.ini
[mypy]
# Python version
python_version = 3.11
# Import discovery
files = src,tests
exclude = build,dist,venv
# Type checking strictness
disallow_untyped_defs = True
disallow_any_unimported = False
no_implicit_optional = True
warn_return_any = True
warn_unused_ignores = True
warn_redundant_casts = True
# Error reporting
show_error_codes = True
show_column_numbers = True
pretty = True
# Incremental type checking
incremental = True
cache_dir = .mypy_cache
# Per-moduRelated in toolchain
nextjs-core
IncludedCore Next.js patterns for App Router development including Server Components, Server Actions, route handlers, data fetching, and caching strategies
nextjs-v16
IncludedNext.js 16 migration guide (async request APIs, "use cache", Turbopack)
vitest
IncludedVitest - Modern TypeScript testing framework with Vite-native performance, ESM support, and TypeScript-first design
mcp-protocol-builder
IncludedMCP (Model Context Protocol) - Build AI-native servers with tools, resources, and prompts. TypeScript/Python SDKs for Claude Desktop integration.
golang-database-patterns
IncludedGo database integration patterns using sqlx, pgx, and migration tools like golang-migrate
sveltekit
IncludedSvelteKit - Full-stack Svelte framework with file-based routing, SSR/SSG, form actions, and adapters for deployment