Skip to main content

behave-pool

CI Documentation PyPI version Python License Code style: ruff

Parallel test execution for Behave BDD via native ITestRunner. Workers run in isolated processes with spawn start method for clean interpreter state on every platform.

Features

  • Native ITestRunner — Registered via --runner= or behave.ini. Zero monkey-patching.
  • Process isolation — spawn start method ensures clean state in every worker, on every OS.
  • Dynamic dispatch — multiprocessing.Process + Queue. Workers consume work units as they finish.
  • @serial tag — Non-parallelizable scenarios run sequentially after the parallel phase.
  • LPT load balancing — Historical durations for optimal work distribution.
  • Timing persistence — .behave-pool-timing.json stores durations between runs.
  • Sharding — Split the suite across CI runners with --shard INDEX/TOTAL. Deterministic, compatible with --parallel and @serial.
  • Unified JSON report — Merges all worker reports into a single behave-modern-json-report ExecutionReport (schema v1.1.0) with statistics, environment info, and full feature/scenario/step details.
  • Ecosystem integration — Optional behave-priority, behave-modern-json-report. The unified report is directly consumable by any tool in the ecosystem.
  • Zero heavy dependencies — Only stdlib multiprocessing + behave>=1.3.0.

Installation

pip install behave-pool

Quick start

behave-pool --parallel 4 features/

behave-pool is a drop-in behave wrapper: it registers the extra --parallel-*/--shard options before behave parses the command line and uses ParallelRunner automatically (unless --runner selects a different one). python -m behave_pool is equivalent.

Prefer the plain behave command? Register the runner alias and set jobs in behave.ini:

[behave]
jobs = 4
runner = behave_pool:ParallelRunner

or map an alias and select it on the command line:

[behave.runners]
parallel = behave_pool:ParallelRunner
behave --runner=parallel --parallel 4 features/

How it works

┌─────────────────────────────────────────────────┐
│                  ParallelRunner                  │
│                                                  │
│  1. Plan    — parse features, create work units  │
│  2. Shard   — select shard slice (if --shard)    │
│  3. Split   — separate @serial from parallel     │
│  4. Dispatch — N parallel workers, then 1 serial │
│  5. Collect — gather results, update timings     │
└─────────────────────────────────────────────────┘
         │                          │
    ┌────▼────┐               ┌────▼────┐
    │ Worker 0 │               │ Worker N │
    │ (spawn)  │    ...        │ (spawn)  │
    │          │               │          │
    │ parse    │               │ parse    │
    │ features │               │ features │
    │ run      │               │ run      │
    │ report   │               │ report   │
    └──────────┘               └──────────┘

Each worker runs in an isolated process with the spawn start method, guaranteeing a clean interpreter state regardless of OS or Python version. Workers consume work units from a shared JoinableQueue and write WorkerResult objects back to a result queue. The coordinator collects results, persists timings, and returns the aggregated exit code.

CLI options

Option Default Description
--parallel N 1 Number of worker processes. 1 = sequential passthrough.
--parallel-scheme feature Parallelization unit: feature or scenario. A scenario unit maps to one Scenario or one whole ScenarioOutline.
--parallel-balance lpt Work ordering: lpt (longest first) or fifo (insertion order).
--parallel-timing-file .behave-pool-timing.json Path to timing file for LPT balancing.
--parallel-report behave-pool-report.json Path to unified JSON report (behave-modern-json-report format).
--shard INDEX/TOTAL (disabled) Run only shard INDEX of TOTAL for CI parallelism across machines.

Usage

Feature-level parallelization

Each feature file runs in its own worker process. Workers are dispatched dynamically and consume work units from a shared queue.

# 4 worker processes, LPT balancing
behave-pool --parallel 4 features/

For finer granularity, --parallel-scheme scenario creates one work unit per scenario (a whole ScenarioOutline counts as a single unit):

behave-pool --parallel 4 --parallel-scheme scenario features/

Serial scenarios

Tag scenarios with @serial to run them sequentially after all parallel work units complete:

@serial
Scenario: Database migration
  Given the database is empty
  When I run the migration
  Then all tables should exist

LPT load balancing

By default, behave-pool uses Longest Processing Time (LPT) scheduling. It stores historical durations in .behave-pool-timing.json and dispatches the slowest features first, minimizing total wall-clock time.

# Use FIFO ordering instead of LPT
behave-pool --parallel 4 --parallel-balance fifo features/

Unified JSON report

After all workers finish, behave-pool merges their results into a single JSON report in the behave-modern-json-report ExecutionReport format (schema v1.1.0). This report includes:

  • Execution metadata — unique ID, status, duration, timestamps.
  • Aggregate statistics — feature/scenario/step counts, pass rate, error count, per-tag breakdown.
  • Environment info — Python and Behave versions, OS, CI provider, git branch/commit.
  • Full feature tree — features, scenarios, and steps with IDs, locations, durations, errors, and tracebacks.
# Default report path
behave-pool --parallel 4 features/
# → writes behave-pool-report.json

# Custom report path
behave-pool --parallel 4 \
    --parallel-report reports/run.json \
    features/

Any tool built for the behave-modern-json-report ecosystem (HTML formatters, dashboards, AI analyzers) can consume the parallel report directly — no conversion needed.

Sharding

Split the test suite across multiple CI runners. Each runner executes only its assigned shard:

# Runner 1 of 3
behave-pool --parallel 4 --shard 1/3 features/

# Runner 2 of 3
behave-pool --parallel 4 --shard 2/3 features/

# Runner 3 of 3
behave-pool --parallel 4 --shard 3/3 features/

Sharding composes with all other features:

  • --parallel: local parallelism within each shard.
  • @serial: serial scenarios run sequentially within the shard.
  • --tags/--name: selection filters are propagated to every worker.
  • --parallel-balance: LPT/FIFO ordering is preserved inside the shard.

The algorithm sorts work units deterministically by ID to compute the shard assignment, then executes them in the planned (LPT/FIFO) order. The first len % TOTAL shards receive one extra work unit.

Output includes shard metadata (logged at INFO level):

Shard 1/3 - 4 work units selected (of 10 total)

Python API:

from behave_pool import ShardConfig, run_with_shard

config = ShardConfig(
    shard_index=1,
    total_shards=3,
    features_dir="features/",
    parallel=4,
)
failed = run_with_shard(config)

behave.ini configuration

Config-file keys must use the option's dest name (underscores, not dashes) — behave reads them verbatim. --parallel maps to jobs:

[behave]
jobs = 4
parallel_scheme = feature
parallel_balance = lpt
parallel_timing_file = .behave-pool-timing.json
parallel_report = behave-pool-report.json
shard = 1/3

The pool keys (parallel_*, shard) are only picked up when the options were registered before behave parses the file — i.e. when using behave-pool / python -m behave_pool. With the plain behave command, use [behave.userdata] entries instead; they are applied when the runner initialises:

[behave]
jobs = 4
runner = behave_pool:ParallelRunner

[behave.userdata]
pool.scheme = feature
pool.balance = fifo
pool.timing_file = .behave-pool-timing.json
pool.report = behave-pool-report.json
pool.shard = 1/3

The same pool.* keys work on the command line via -D:

behave --runner=behave_pool:ParallelRunner -D pool.jobs=4 -D pool.shard=1/3

Requirements

  • Python >=3.11
  • behave >=1.3.0

Example

A complete working example is included in examples/calculator/. It demonstrates parallel execution, @serial scenarios, and the unified JSON report:

cd examples/calculator
behave-pool --parallel 4
# → runs 3 scenarios (2 parallel + 1 @serial)
# → writes behave-pool-report.json with ExecutionReport format

Documentation

Full documentation is available at https://mathiaspaulenko.github.io/behave-pool/.

Contributing

Contributions are welcome! See CONTRIBUTING.md for setup instructions and guidelines.

Please review our Code of Conduct before participating.

Changelog

See CHANGELOG.md for notable changes.

License

MIT — Copyright (c) 2026 Mathias Paulenko

Acknowledgements

Metadata

Release files for behave-pool 1.3.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 behave-pool 1.3.0
File Size Uploaded
behave_pool-1.3.0.tar.gz 90.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for behave-pool 1.3.0
File Interpreter ABI Platform
behave_pool-1.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 125.7 kB

Release files / behave_pool-1.3.0.tar.gz

Download URL behave_pool-1.3.0.tar.gz
Size 90.4 kB
Tags Source
SHA-256 checksum
How to use checksums
d6d0442c92bed4ccfd65dad9f1f80a572ba52fa13c61fad4810e3f9f95922e7d
BLAKE2b-256 checksum
How to use checksums
b369deb86e786ade70984b6ac05e62a3fb3b015e68bad84fca7b6857cae07ee6
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 Oct 4, 2026.

Transparency log

Release files / behave_pool-1.3.0-py3-none-any.whl

Download URL behave_pool-1.3.0-py3-none-any.whl
Size 35.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1070e193ba09d82c0b4b83ea9e998e633bcc11c6ab1da63aad7033797b0c5513
BLAKE2b-256 checksum
How to use checksums
2d8c55ce08110471fc5d5d5162141cd7102285cccd06ce196b23ef00745a7436
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 Oct 4, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.3.0 This release

2 release files

1.2.0

2 release files

1.1.3

2 release files

1.1.2

2 release files

1.0.0

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