typemut¶
Mutation testing for Python type annotations.
Standard mutation testing tools (cosmic-ray, mutmut) mutate runtime code and check if tests catch it. typemut mutates only type annotations and checks if type checkers (mypy, pyright) catch the change.
- Mutant killed = type checker reports an error (types are strict enough)
- Mutant survived = no type error (types are too loose or type checker coverage is weak)
- Mutant error = the mutant broke the code itself (e.g. an undefined name), excluded from the mutation score
# Original
def greet(name: str | None) -> str: ...
# Mutant: remove None — survives if no caller ever passes None
def greet(name: str) -> str: ...
Features¶
- 8 operators — remove union/literal members, add or remove
Optional, widen types to their bases and containers to abstract ones, swapIterator/Generator, changeTypeVarvariance. - Type checkers — mypy, pyright, basedpyright, any other command
via the generic checker, and third-party checker plugins. False kills from broken
mutants are reported as
error. - Parallel runs —
--jobs Nruns mutants in N git worktrees. - CI gating —
--fail-underand a baseline of accepted survivors. - GitHub Action —
uses: nkhitrov/typemut@<release>runs typemut incrementally and keeps the database of the default branch as an artifact. - Incremental runs — reuse kills whose files are unchanged; recipes to keep the database between CI runs on GitHub Actions and GitLab CI.
- Plugins — SQLAlchemy, FastAPI, FastStream, django-modern-rest, pydantic and taskiq, framework entrypoints, third-party plugins.
- Filtering — skip comments, excluded modules,
@overridesignatures, ignored types and class hierarchies. - HTML report with per-mutant diffs and checker output.
Start with Getting started.