Skip to main content

pytest-fsplit

pytest-fsplit is a pytest plugin for splitting a test suite into deterministic file-level shards before pytest imports and collects unselected files. This is in contrast with plugins like pytest-split which collect fully and then deselect in each shard. In large test code bases this collection step can take up multiple minutes and keeps taking longer as you add more tests. In pytest-fsplit the collection is a lot faster and stays proportional to shard size. In our own codebase with 18k tests and 1.5k test files, pytest-fsplit takes 40s vs pytest-split which takes 3 mins to collect tests.

pytest-fsplit reads a pytest-split-compatible JSON duration file, aggregates node timings by test file, assigns files to shards with a longest-processing-time-first plan, and uses pytest_ignore_collect to prune files and directories outside the selected shard.

Installation

pip install pytest-fsplit

Usage

First record durations from a complete, unsharded run:

pytest --fsplit-store-durations

Then run each file shard separately:

pytest --fsplits 4 --fgroup 1
pytest --fsplits 4 --fgroup 2
pytest --fsplits 4 --fgroup 3
pytest --fsplits 4 --fgroup 4

The duration file defaults to .test_durations in the invocation directory and can be changed with --fsplit-durations-path.

pytest-fsplit intentionally uses distinct option names. If pytest-split is installed too, --splits and --group continue to belong to pytest-split; use --fsplits and --fgroup for file-level pre-collection sharding.

The default file splitting algorithm is least_duration, which greedily assigns the next heaviest file to the lightest shard. To preserve contiguous lexical file order instead, use duration_based_chunks:

pytest --fsplits 4 --fgroup 1 --fsplit-algorithm duration_based_chunks

When nbval is active through --nbval or --nbval-lax, pytest-fsplit treats .ipynb notebooks as shardable files automatically. For other non-Python collectors, provide the file patterns pytest-fsplit should treat as shardable files:

pytest --fsplit-file-pattern "*.case" --fsplits 4 --fgroup 1

Stored duration files can be inspected from the command line:

fsplit-plan --fsplits 4
fsplit-slowest-tests --count 10
slowest-tests --count 10
fsplit-slowest-files --count 10

Use fsplit-plan --fsplits 4 --show-files to see file assignments, or fsplit-plan --fsplits 4 --json for machine-readable output.

Behavior

  • Shard indices are one-based.
  • Both --fsplits and --fgroup must be supplied together.
  • If there are more shards than candidate files, planned empty shards exit successfully.
  • --fsplit-algorithm supports least_duration and duration_based_chunks.
  • Files without historical timings use the median known file duration.
  • Stale timing entries for deleted files are ignored.
  • Missing, malformed, or unusable duration files fail immediately when sharding.
  • --fsplit-store-durations writes the same node-duration JSON shape used by pytest-split.
  • Older pytest-split list-of-pairs duration files are accepted when reading.
  • --fsplit-store-durations cannot be combined with sharding because it would record only the selected shard.
  • --fsplit-clean-durations is valid only with --fsplit-store-durations.

Compatibility

pytest-fsplit runs before collection, so it avoids the full-suite collection cost paid by post-collection splitters. It honors pytest collection roots, python_files, --ignore, --ignore-glob, norecursedirs, explicit file arguments, marker deselection, and xdist worker startup.

If pytest-split is installed too, do not combine --fsplits/--fgroup with pytest-split's --splits/--group or --store-durations; pytest-fsplit rejects those combinations to avoid applying two independent partitions or recording timings for only one file shard.

Unlike pytest-split's post-collection grouping, pytest-fsplit groups whole files before collection. That means test-order randomization plugins can still reorder items inside the selected files without changing which files belong to a shard.

When nbval is active, .ipynb files are assigned as whole-file shards automatically. For other file-backed collectors, include those file names with --fsplit-file-pattern. Pytest-fsplit assigns whole files to shards, so it will not split one notebook or custom collected file across several groups.

Development

uv sync --extra dev
uv run ruff check .
uv run pytest -q
uv build

Release files for pytest-fsplit 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pytest-fsplit 0.1.0
File Size Uploaded
pytest_fsplit-0.1.0.tar.gz 100.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pytest-fsplit 0.1.0
File Interpreter ABI Platform
pytest_fsplit-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 122.2 kB

Release files / pytest_fsplit-0.1.0.tar.gz

Download URL pytest_fsplit-0.1.0.tar.gz
Size 100.2 kB
Tags Source
SHA-256 checksum
How to use checksums
861cccd7ca4fa8a64a844e4945c9d49fec4aaa6d77cf376e4a07045bf1a0c494
BLAKE2b-256 checksum
How to use checksums
4701e81114fa276060bf167635f7b4aca25da93599231bba59c021877de2847e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 20, 2026.

Transparency log

Release files / pytest_fsplit-0.1.0-py3-none-any.whl

Download URL pytest_fsplit-0.1.0-py3-none-any.whl
Size 21.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1609cfc537c0ddbdde84a05f7ed354cd7e64d80ea55cdb911b08b6845da8a3a3
BLAKE2b-256 checksum
How to use checksums
e04428adcf636653979993b771116a0be80ce973753986a3a3b8373da6843112
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 20, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page