Skip to main content

Type-aware mutation testing for Python — fast, opinionated, pytest-native

Project description

pytest-leela

Type-aware mutation testing for Python.

PyPI version Python versions License CI


What it does

pytest-leela runs mutation testing inside your existing pytest session. It injects AST mutations via import hooks (no temp files), maps each mutation to only the tests that cover that line, and uses type annotations to skip mutations that can't possibly fail your tests.

It's opinionated: we target latest Python, favour speed over configurability, and integrate with pytest without separate config files or runners. If that fits your workflow, great. MIT licensed — fork it if it doesn't.


Install

pip install pytest-leela

Quick Start

Run mutation testing on your whole test suite:

pytest --leela

When no --target is given, pytest-leela auto-discovers source files:

  1. Looks for a target/ or src/ directory (in that order) and mutates all .py files inside it
  2. If neither exists, falls back to the project root (skipping .venv, build, dist, __pycache__, node_modules, .git, and similar non-source directories)

Test files (test_*.py, *_test.py, conftest.py, tests.py) are always excluded from mutation.

Exclude patterns from [tool.pytest-leela] (see Configuration) are applied after target discovery, so you can auto-discover src/ while still excluding specific paths.

Target specific modules (pass --target multiple times):

pytest --leela --target myapp/models.py --target myapp/views.py

Only mutate lines changed vs a branch:

pytest --leela --diff main

Limit CPU cores:

pytest --leela --max-cores 4

Cap memory usage:

pytest --leela --max-memory 4096

Combine flags:

pytest --leela --diff main --max-cores 4 --max-memory 4096

Generate an interactive HTML report:

pytest --leela --leela-html report.html

Benchmark optimization layers:

pytest --leela-benchmark

Features

  • Type-aware mutation pruning — uses type annotations to skip mutations that can't possibly trip your tests (e.g. won't swap + to - on a str operand)
  • Per-test coverage mapping — each mutant runs only the tests that exercise its lines, not the whole suite
  • In-process execution via import hooks — mutations applied via sys.meta_path, zero filesystem writes, fast loop
  • Git diff mode--diff <ref> limits mutations to lines changed since that ref
  • Framework-aware — clears Django URL caches between mutants so view reloads work correctly
  • Resource limits--max-cores N caps parallelism; --max-memory MB guards memory
  • HTML report--leela-html generates an interactive single-file report with source viewer, survivor navigation, and test source overlay
  • CI exit codes — exits non-zero when mutants survive, so CI pipelines fail on incomplete kill rates
  • Benchmark mode--leela-benchmark measures the speedup from each optimization layer

Configuration

Configure pytest-leela in your pyproject.toml under [tool.pytest-leela]:

[tool.pytest-leela]
exclude = [
    "*/migrations/*",
    "manage.py",
    "*/conftest.py",
]
operators = [
    "arithmetic",
    "comparison",
    "boolean",
    "return",
]

exclude

A list of glob patterns. Files whose path (relative to the project root) matches any pattern are excluded from mutation. Uses fnmatch matching — * matches within a single directory, */migrations/* matches any migrations directory at any depth.

Default: [] (nothing excluded).

operators

A list of operator category names controlling which mutation types are applied. Use "all" as a shorthand to enable every category.

Default: ["arithmetic", "comparison", "boolean", "unary", "return"]

Category What it mutates Default
arithmetic + - * / // % ** on
comparison == != < <= > >= is in and negations on
boolean and / or on
unary unary - + not on
return return values (True/False, None, literals, expressions) on
bitwise & | ^ << >> off
augmented_assign += -= *= etc. off
ternary x if cond else y branch swaps off
control_flow break / continue swaps off
exception except handler broadening, body-to-raise off

Pragma Skip

Add # leela: skip to suppress mutations on individual lines:

result = x + y  # leela: skip

To skip an entire file, place the pragma on line 1:

# leela: skip
"""This module is excluded from mutation testing."""

def legacy_code():
    ...

The pragma is detected via Python's tokenize module, so it only matches actual comments — not string literals or docstrings that happen to contain the text.


HTML Report

--leela-html report.html generates a single self-contained HTML file with no external dependencies.

What it shows:

  • Overall mutation score badge
  • Per-file breakdown with kill/survive/timeout counts
  • Source code viewer with syntax highlighting

Interactive features:

  • Click any line to see mutant details (original → mutated code, status, relevant tests)
  • Survivor navigation overlay — keyboard shortcuts: n next survivor, p previous, l list all, Esc close
  • Test source overlay — click any test name to see its source code

Uses the Catppuccin Mocha dark theme.


Requirements

  • Python >= 3.12
  • pytest >= 7.0

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytest_leela-0.4.0.tar.gz (118.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pytest_leela-0.4.0-py3-none-any.whl (49.1 kB view details)

Uploaded Python 3

File details

Details for the file pytest_leela-0.4.0.tar.gz.

File metadata

  • Download URL: pytest_leela-0.4.0.tar.gz
  • Upload date:
  • Size: 118.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pytest_leela-0.4.0.tar.gz
Algorithm Hash digest
SHA256 6c0ba8ddd1d24dbf5a576810fe1664d0d18d2112e0401a54d17400fdb70b4bdf
MD5 6bccf0700c48efb99a271c3c6724e5df
BLAKE2b-256 89d094e9f15d9972845b6559bb150cd05b4144a44c82123399b723072057d928

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytest_leela-0.4.0.tar.gz:

Publisher: publish.yml on markng/pytest-leela

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pytest_leela-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: pytest_leela-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 49.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pytest_leela-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 89fb3f614146883f45737443a4c1cc6c59a02d583bc1c56e6726496b9a96646c
MD5 4b11a6c0d0cce01b2936eb2ac2e59dfb
BLAKE2b-256 566a3f61f1f3550e4eef2f09b26b05fb1dca587139249b90f5d00ce269408d1a

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytest_leela-0.4.0-py3-none-any.whl:

Publisher: publish.yml on markng/pytest-leela

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page