Skip to main content

An extremely fast mutation testing tool for Python

Project description

fest

An extremely fast mutation testing tool for Python.

PyPI License Rust Python


fest generates small changes (mutants) to your Python source code and checks whether your test suite catches them. Surviving mutants reveal gaps that line coverage alone cannot find.

Built in Rust with ruff's Python parser. ~25× faster than cosmic-ray on real-world projects (benchmark).

Highlights

  • 🔥 Parallel execution — runs mutants across all CPU cores simultaneously
  • 🎯 Coverage-guided — only runs tests that cover the mutated line, via per-test pytest-cov context
  • In-process plugin — a persistent pytest worker pool avoids per-mutant startup overhead
  • 🧬 17 mutation operators — arithmetic, comparison, boolean, return value, constants, decorators, loops, and more
  • 📊 Multiple output formats — text, JSON, and self-contained HTML reports
  • 🔄 Session support — stop and resume long runs with SQLite-backed sessions

Installation

From PyPI (recommended)

pip install fest-mutate

From source

git clone https://github.com/sakost/fest.git
cd fest
cargo build --release

The binary will be at target/release/fest. Make sure pytest and pytest-cov are installed in the Python environment you want to test:

pip install pytest pytest-cov

Quick start

cd your-python-project
fest run

fest will:

  1. Discover Python source files matching src/**/*.py (configurable)
  2. Run pytest with coverage to build a per-test line map
  3. Generate mutants from the discovered source
  4. Test each mutant against only the relevant tests
  5. Print a summary report
fest — mutation testing for Python

  Configuration loaded (fest.toml)  0ms
  Mutator registry built (14 mutators)  0ms
  Source files discovered (14 files)  0ms
  Mutants generated (4290 mutants)  23ms
  Coverage collected  40ms
  Session opened (.fest-session.db)  0ms
  Test workers ready (24 workers)  994ms
  Mutants tested (4186 mutants)  4m 6s

  Mutation Score: 85.7%  |  Killed: 2401  Survived: 314  Timeout: 80  Errors: 8

Configuration

Create fest.toml in your project root (or add [tool.fest] to pyproject.toml):

[fest]
source = ["src/**/*.py"]
exclude = ["**/test_*.py", "**/conftest.py"]
timeout = 30
workers = 8                    # default: 75% of CPU cores
fail_under = 80.0              # exit 1 if score is below this
output = "text"                # "text", "json", or "html"
backend = "plugin"             # "plugin" or "subprocess"
session = ".fest-session.db"   # enable stop/resume

All fields are optional — fest picks sensible defaults.

CLI

fest run [OPTIONS]
Flag Description
-s, --source <GLOB> Source file patterns
-e, --exclude <GLOB> Exclude patterns
-w, --workers <N> Parallel test workers
-t, --timeout <SEC> Per-test timeout (default: 10)
--fail-under <SCORE> Minimum mutation score (0–100)
-o, --output <FMT> text · json · html
-b, --backend <BE> plugin (default) · subprocess
--coverage-from <PATH> Use existing .coverage file
--session <PATH> SQLite session for stop/resume
--reset Reset session before running
--incremental Only re-test changed files
--seed <N> Deterministic mutation seed
--filter-operators <PAT> Include/exclude operators by name
--filter-paths <GLOB> Restrict mutation to matching files
--progress <STYLE> auto · fancy · plain · verbose · quiet
-v, --verbose Per-mutant progress output

Mutation operators

Operator Example
arithmetic_op x + yx - y
augmented_assign x += 1x -= 1
bitwise_op a & ba | b
boolean_op a and ba or b
break_continue breakcontinue
comparison_op a == ba != b
constant_replace TrueFalse, 01
exception_swallow raise Error()pass
negate_condition if x:if not x:
remove_decorator @cache(removed)
remove_super super().__init__()(removed)
return_value return valreturn None
statement_deletion do_something()pass
unary_op -xx, ~xx
variable_replace a = xa = y (same-scope same-type)
variable_insert a = f(x)a = f(y)
zero_iteration for x in items:for x in []:

Backends

Backend How it works Speed Compatibility
plugin (default) Patches modules in a long-lived pytest process ⚡ Fast Most projects
subprocess Overwrites source file on disk, runs pytest Slower Universal

The plugin backend falls back to subprocess automatically on infrastructure errors.

Performance

On python-ecdsa (17k lines, 1,477 tests):

fest cosmic-ray
Throughput 17.4 mut/s 0.7 mut/s
Time to complete 4 min ~6 hours (estimated)
Speedup ~25× baseline

See the full benchmark report for methodology and reproduction steps.

License

Dual-licensed under MIT or Apache-2.0, at your option.

Project details


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

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

fest_mutate-0.1.3-py3-none-win_amd64.whl (2.9 MB view details)

Uploaded Python 3Windows x86-64

fest_mutate-0.1.3-py3-none-manylinux_2_39_x86_64.whl (3.1 MB view details)

Uploaded Python 3manylinux: glibc 2.39+ x86-64

fest_mutate-0.1.3-py3-none-manylinux_2_39_aarch64.whl (3.0 MB view details)

Uploaded Python 3manylinux: glibc 2.39+ ARM64

fest_mutate-0.1.3-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl (3.2 MB view details)

Uploaded Python 3manylinux: glibc 2.5+ x86-64

fest_mutate-0.1.3-py3-none-macosx_11_0_arm64.whl (2.9 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

fest_mutate-0.1.3-py3-none-macosx_10_12_x86_64.whl (3.0 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file fest_mutate-0.1.3-py3-none-win_amd64.whl.

File metadata

  • Download URL: fest_mutate-0.1.3-py3-none-win_amd64.whl
  • Upload date:
  • Size: 2.9 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fest_mutate-0.1.3-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 98b68e7080485915f9c30f917d05af1b4a663eec9e47cf12b99b0a17a07627ea
MD5 65c725d0926a48c83e141f8f1d20e0b6
BLAKE2b-256 fbba818ab6c6741afdc7624c38a7e809fe67841577cab13f8baecbe0fdf1b8bc

See more details on using hashes here.

Provenance

The following attestation bundles were made for fest_mutate-0.1.3-py3-none-win_amd64.whl:

Publisher: release-please.yml on sakost/fest

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

File details

Details for the file fest_mutate-0.1.3-py3-none-manylinux_2_39_x86_64.whl.

File metadata

File hashes

Hashes for fest_mutate-0.1.3-py3-none-manylinux_2_39_x86_64.whl
Algorithm Hash digest
SHA256 05d137c5e19146417f171846d0c3af522d734cf52db9d963ae8a8cca16944679
MD5 7cf2cb43fe7714876ff9abe691ddac68
BLAKE2b-256 07caff32e42a775c5f28684e4d7ee31ca344edca82de06b17540ed45c30fa44e

See more details on using hashes here.

Provenance

The following attestation bundles were made for fest_mutate-0.1.3-py3-none-manylinux_2_39_x86_64.whl:

Publisher: release-please.yml on sakost/fest

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

File details

Details for the file fest_mutate-0.1.3-py3-none-manylinux_2_39_aarch64.whl.

File metadata

File hashes

Hashes for fest_mutate-0.1.3-py3-none-manylinux_2_39_aarch64.whl
Algorithm Hash digest
SHA256 78931d8aa80cc1eb4ec5cc66a91219f5d4eaff48ba9d3cdcd94002cef942981e
MD5 ab4e9ecea7e11fcea6acff2befbf5c51
BLAKE2b-256 7dc87eb55991496419d1fd7a309d1610c0b1a094b2967399bbea99686aa25178

See more details on using hashes here.

Provenance

The following attestation bundles were made for fest_mutate-0.1.3-py3-none-manylinux_2_39_aarch64.whl:

Publisher: release-please.yml on sakost/fest

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

File details

Details for the file fest_mutate-0.1.3-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for fest_mutate-0.1.3-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 d6e71b84b5c8fda7a7b7c22ff6d86cdbb49b4097c889b6ef393b1227588b0754
MD5 b96d7c1b748e607aab6c39d28ba2bc73
BLAKE2b-256 955951ab024b4cd1b2ee61573c9417c1cd02a72574ebe18b7f737d19e9de9ecb

See more details on using hashes here.

Provenance

The following attestation bundles were made for fest_mutate-0.1.3-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl:

Publisher: release-please.yml on sakost/fest

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

File details

Details for the file fest_mutate-0.1.3-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for fest_mutate-0.1.3-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 8d26d81149e4dff39a1ea0c1593e238a67d7952fcb6cf6f2cdc0d4219c736666
MD5 65f381d1e0571489c68ae4e230c3e4d2
BLAKE2b-256 12aa60f1de73f03aaf4e8cc6e822d6e82e54b072a8f645e5b5c009bc32a374a0

See more details on using hashes here.

Provenance

The following attestation bundles were made for fest_mutate-0.1.3-py3-none-macosx_11_0_arm64.whl:

Publisher: release-please.yml on sakost/fest

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

File details

Details for the file fest_mutate-0.1.3-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for fest_mutate-0.1.3-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 f538884b0c7ddd1260dbae9d0bf4fe221f5b62872fcd4cdec854701d3fd57615
MD5 434111df31d7a5f4d62f4ef9cfa5cd04
BLAKE2b-256 2ecc3645b68b0b8373a95f455c09c0a1bfa72d14937c977b2f7a5bc0de10c25f

See more details on using hashes here.

Provenance

The following attestation bundles were made for fest_mutate-0.1.3-py3-none-macosx_10_12_x86_64.whl:

Publisher: release-please.yml on sakost/fest

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