python-mypy
Static type checking with Mypy for Python code quality. Use when writing or reviewing Python code to ensure type safety, catch bugs early, and maintain code quality through proper type annotations and Mypy configuration.
What this skill does
# Python Mypy Type Checking Skill
This skill automatically activates when writing Python code to ensure proper type annotations and compatibility with Mypy static type checking.
## Core Principles
- **Type Safety**: Catch type errors before runtime
- **Gradual Typing**: Start with critical paths, expand coverage over time
- **Strict Mode**: Enable strict checks for new code
- **CI Integration**: Run Mypy in continuous integration
## Type Annotation Patterns
### Function Signatures
```python
from typing import Optional
from collections.abc import Sequence
# Good: Complete type hints
def process_items(
items: list[str],
max_count: int | None = None,
debug: bool = False,
) -> dict[str, int]:
"""Process items and return counts."""
result: dict[str, int] = {}
# Implementation
return result
# Good: Generic types with TypeVar
from typing import TypeVar
T = TypeVar('T')
def first(items: Sequence[T]) -> T | None:
"""Get first item from sequence."""
return items[0] if items else None
```
### Class Type Hints
```python
from typing import ClassVar
from dataclasses import dataclass
@dataclass
class User:
"""User model with type hints."""
id: int
name: str
email: str | None = None
active: bool = True
# Class variable
_registry: ClassVar[dict[int, 'User']] = {}
def __post_init__(self) -> None:
"""Register user after initialization."""
self._registry[self.id] = self
```
### Protocol for Structural Typing
```python
from typing import Protocol
class Drawable(Protocol):
"""Protocol for drawable objects."""
def draw(self) -> str:
"""Draw the object."""
...
def render(obj: Drawable) -> None:
"""Render any drawable object."""
print(obj.draw())
# Any class with draw() method satisfies this
class Circle:
def draw(self) -> str:
return "○"
render(Circle()) # OK with Mypy
```
### TypedDict for Structured Dictionaries
```python
from typing import TypedDict, NotRequired
class UserDict(TypedDict):
"""Structured user dictionary."""
id: int
name: str
email: NotRequired[str] # Optional key (Python 3.11+)
def create_user(data: UserDict) -> None:
"""Create user from typed dictionary."""
user_id: int = data["id"] # Type-safe access
# Mypy knows 'email' might not exist
```
## Mypy Configuration Best Practices
### Recommended mypy.ini
```ini
[mypy]
python_version = 3.11
warn_return_any = True
warn_unused_configs = True
disallow_untyped_defs = True
disallow_any_generics = True
disallow_subclassing_any = True
disallow_untyped_calls = True
disallow_incomplete_defs = True
check_untyped_defs = True
no_implicit_optional = True
warn_redundant_casts = True
warn_unused_ignores = True
warn_no_return = True
warn_unreachable = True
strict_equality = True
show_error_codes = True
show_column_numbers = True
# Start strict, relax per-module if needed
[mypy-tests.*]
disallow_untyped_defs = False
[mypy-migrations.*]
ignore_errors = True
# Third-party without stubs
[mypy-some_library.*]
ignore_missing_imports = True
```
### pyproject.toml Configuration
```toml
[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
show_error_codes = true
[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false
[[tool.mypy.overrides]]
module = "migrations.*"
ignore_errors = true
```
## Common Mypy Checks
### Strict Optional Checking
```python
# Bad: Implicit Optional
def find_user(id: int) -> User: # Mypy error if can return None
return users.get(id) # dict.get returns User | None
# Good: Explicit Optional
def find_user(id: int) -> User | None:
return users.get(id)
# Good: Narrow type with assertion
def get_user(id: int) -> User:
user = users.get(id)
assert user is not None, f"User {id} not found"
return user # Mypy knows this is User, not None
```
### Type Narrowing
```python
def process(value: str | int) -> str:
"""Process value based on type."""
if isinstance(value, str):
# Mypy knows value is str here
return value.upper()
else:
# Mypy knows value is int here
return str(value * 2)
```
### Generics
```python
from typing import Generic, TypeVar
T = TypeVar('T')
class Stack(Generic[T]):
"""Type-safe stack."""
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()
# Usage
int_stack: Stack[int] = Stack()
int_stack.push(1) # OK
int_stack.push("x") # Mypy error!
```
## Type Checking Strategies
### Gradual Adoption
1. **Start with New Code**: Use strict mode for new modules
2. **Core Paths First**: Type-check critical business logic
3. **Expand Coverage**: Gradually increase `disallow_untyped_defs`
4. **Per-Module Configuration**: Use mypy overrides for legacy code
```ini
[mypy]
# Strict by default
disallow_untyped_defs = True
# Relax for legacy
[mypy-legacy.*]
disallow_untyped_defs = False
check_untyped_defs = True # Still check what we can
```
### Type Ignores (Use Sparingly)
```python
# When third-party library lacks types
import untyped_library # type: ignore[import-untyped]
# When dealing with dynamic code (rare)
def dynamic_call() -> Any:
result = getattr(obj, method_name)() # type: ignore[misc]
return result
```
## Common Patterns
### Context Managers
```python
from typing import Generator
from contextlib import contextmanager
@contextmanager
def database_transaction() -> Generator[Connection, None, None]:
"""Type-safe context manager."""
conn = get_connection()
try:
yield conn
conn.commit()
except Exception:
conn.rollback()
raise
finally:
conn.close()
```
### Callable Types
```python
from collections.abc import Callable
def retry(
func: Callable[[int], str],
times: int = 3,
) -> str:
"""Retry a function that takes int and returns str."""
for _ in range(times):
try:
return func(42)
except Exception:
continue
raise RuntimeError("All retries failed")
```
### Overloads for Multiple Signatures
```python
from typing import overload
@overload
def parse(data: str) -> dict[str, str]: ...
@overload
def parse(data: bytes) -> dict[str, bytes]: ...
def parse(data: str | bytes) -> dict[str, str] | dict[str, bytes]:
"""Parse data with type-specific return."""
if isinstance(data, str):
return {"parsed": data}
return {"parsed": data}
```
## Django Integration
### Model Type Hints
```python
from django.db import models
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from django.db.models.manager import RelatedManager
class Author(models.Model):
name = models.CharField(max_length=100)
if TYPE_CHECKING:
books: RelatedManager['Book']
class Book(models.Model):
title = models.CharField(max_length=200)
author: models.ForeignKey[Author] = models.ForeignKey(
Author,
on_delete=models.CASCADE,
related_name='books',
)
```
### Django Mypy Plugin
```ini
[mypy]
plugins = mypy_django_plugin.main
[mypy.plugins.django-stubs]
django_settings_module = "myproject.settings"
```
## Running Mypy
### Basic Check
```bash
# Check all files
mypy .
# Check specific files/directories
mypy src/
# Show error codes
mypy --show-error-codes .
# Generate HTML report
mypy --html-report ./mypy-report .
```
### In CI/CD
```yaml
# .github/workflows/type-check.yml
- name: Type check with Mypy
run: |
pip install mypy
mypy --strict src/
```
## Anti-Patterns to Avoid
### Don't Use `Any` Unnecessarily
```python
# Bad: Any hides all type errors
def process(data: Any) -> Any:
return data.unknown_method() # No error!
# Good: Use specific types
def process(data: dict[str, int]) -> list[int]:
return list(data.values())
```
### DRelated in Writing & Docs
jax-development
IncludedUse this skill when the user is writing, debugging, profiling, refactoring, reviewing, benchmarking, parallelising, exporting, or explaining JAX code, or when they mention JAX, jax.numpy, jit, grad, value_and_grad, vmap, scan, lax, random keys, pytrees, jax.Array, sharding, Mesh, PartitionSpec, NamedSharding, pmap, shard_map, Pallas, XLA, StableHLO, checkify, profiler, or the JAX repo. It helps turn NumPy or PyTorch-style code into pure functional JAX, fix tracer/control-flow/shape/PRNG bugs, remove recompiles and host-device syncs, choose transforms and sharding strategies, inspect jaxpr/lowering/IR, and benchmark compiled code correctly.
nature-article-writer
IncludedDrafts, rewrites, diagnostically critiques, and style-calibrates primary research manuscripts for Nature and Nature Portfolio journals. Use when the user wants a Nature-style title, summary paragraph or abstract, introduction, results, discussion, methods, figure legends, presubmission enquiry, cover letter, reviewer response, or when a scientific draft sounds generic, jargon-heavy, structurally weak, or AI-ish and needs precise, broad-reader-friendly prose without inventing data, analyses, or references. Best for primary research articles and letters rather than reviews or press releases unless explicitly adapting one.
deckrd
IncludedDocument-driven framework that derives requirements, specifications, implementation plans, and executable tasks from goals through structured AI dialogue. Use when user says "write requirements", "create spec", "plan implementation", "derive tasks", "structure this feature", "break down into tasks", or "document this module". Also use for reverse engineering existing code into docs (/deckrd rev). Do NOT use for direct code writing — use /deckrd-coder after tasks are generated. Do NOT use when the user only wants to run or fix existing code without planning.
clinical-decision-support
IncludedGenerate professional clinical decision support (CDS) documents for pharmaceutical and clinical research settings, including patient cohort analyses (biomarker-stratified with outcomes) and treatment recommendation reports (evidence-based guidelines with decision algorithms). Supports GRADE evidence grading, statistical analysis (hazard ratios, survival curves, waterfall plots), biomarker integration, and regulatory compliance. Outputs publication-ready LaTeX/PDF format optimized for drug development, clinical research, and evidence synthesis.
handling-sf-data
IncludedSalesforce data operations with 130-point scoring. Use this skill to create, update, delete, bulk import/export, generate test data, and clean up org records using sf CLI and anonymous Apex. TRIGGER when: user creates test data, performs bulk import/export, uses sf data CLI commands, needs data factory patterns for Apex tests, or needs to seed/clean records in a Salesforce org. DO NOT TRIGGER when: SOQL query writing only (use querying-soql), Apex test execution (use running-apex-tests), or metadata deployment (use deploying-metadata).
accelint-ac-to-playwright
IncludedConvert and validate acceptance criteria for Playwright test automation. Use when user asks to (1) review/evaluate/check if AC are ready for automation, (2) assess if AC can be converted as-is, (3) validate AC quality for Playwright, (4) turn AC into tests, (5) generate tests from acceptance criteria, (6) convert .md bullets or .feature Gherkin files to Playwright specs, (7) create test automation from requirements. Handles both bullet-style markdown and Gherkin syntax with JSON test plan generation and validation.