Behave Hooks¶
The hooks module provides the integration layer between behave-priority
and behave’s lifecycle. It exposes functions for before_all,
before_scenario, after_scenario, and after_all hooks.
- behave_priority.hooks._scenario_key = <function _scenario_key>[source]
Build a deterministic key for a scenario.
Uses
filenameandlineattributes when available (as behave provides), falling back toid()for objects without them.- Parameters:
scenario – The scenario object.
- Returns:
A string key unique to the scenario.
- behave_priority.hooks.setup_priority(context: Any, *, order: bool = False, reverse: bool = False, priority_tag: str | None = None, stop_after_failures: int | None = None, stop_on_critical: bool = False, critical_tag: str = 'critical', default_priority: int = 999, report: bool = False, report_format: Literal['text', 'json', 'csv'] = 'text', parallel_coord: bool = False) None[source]¶
Set up priority execution in before_all hook.
All configuration is passed explicitly — no CLI flags.
- Parameters:
context – Behave’s context object (
contextinbefore_all).order – Sort scenarios by priority (highest first).
reverse – Reverse sort order (lowest priority first).
priority_tag – Tag name to run first (e.g.
"smoke").stop_after_failures – Stop after N failed scenarios.
stop_on_critical – Stop if any critical scenario fails.
critical_tag – Tag name that marks a scenario as critical.
default_priority – Priority for scenarios without a priority tag.
report – Print execution report after run.
report_format – Output format for the report (
"text","json","csv").parallel_coord – Enable cross-process fail-fast coordination. Requires
BEHAVE_PRIORITY_COORD_DIRenv var to be set.
- behave_priority.hooks.before_scenario_hook(context: Any, scenario: Any) None[source]¶
Skip scenario if fail-fast has been triggered.
Intended for use as
before_scenarioin behave’senvironment.py. Recording of skipped scenarios is handled byafter_scenario_hookto avoid duplicate entries.- Parameters:
context – Behave’s context object.
scenario – The scenario about to run.
- behave_priority.hooks.after_scenario_hook(context: Any, scenario: Any) None[source]¶
Record scenario result and update fail-fast state.
Intended for use as
after_scenarioin behave’senvironment.py. Both executed and skipped scenarios are recorded here to avoid duplicate entries.- Parameters:
context – Behave’s context object.
scenario – The scenario that just finished.
- behave_priority.hooks.get_report(context: Any) PriorityReport | None[source]¶
Retrieve the priority execution report from context.
Allows programmatic access to the
PriorityReportobject after a run, without accessing the privatecontext._priority_state.- Parameters:
context – Behave’s context object.
- Returns:
The
PriorityReportif priority state was set up, otherwise None.
- behave_priority.hooks.priority_report(context: Any) None[source]¶
Print the priority execution report.
Intended for use as
after_allin behave’senvironment.py.- Parameters:
context – Behave’s context object.
PriorityState¶
- class behave_priority.hooks.PriorityState(config: PriorityConfig, report: PriorityReport, sorter: ScenarioSorter, coordinator: ParallelCoordinator | None = None, failed_count: int = 0, critical_failed: bool = False, should_stop: bool = False, executed_count: int = 0, skipped_count: int = 0, priority_map: dict[str, int]=<factory>, feature_map: dict[str, str]=<factory>, rule_tag_map: dict[str, list[str]]=<factory>, feature_tag_map: dict[str, list[str]]=<factory>)[source]¶
Bases:
objectMutable execution state, persisted across hooks via context.
Note
This state is not shared across processes. When behave runs with
--parallel, each worker process gets its own isolatedPriorityState. However, whenparallel_coord=TrueandBEHAVE_PRIORITY_COORD_DIRis set, aParallelCoordinatorshares fail-fast state across workers via file-based IPC.- Variables:
config (behave_priority.config.PriorityConfig) – The priority configuration.
report (behave_priority.report.PriorityReport) – The execution report collector.
sorter (behave_priority.sorter.ScenarioSorter) – The scenario sorter instance.
coordinator (behave_priority.parallel.ParallelCoordinator | None) – Optional parallel coordinator for cross-process fail-fast. None when
parallel_coordis disabled.failed_count (int) – Number of failed scenarios so far.
critical_failed (bool) – Whether any critical scenario has failed.
should_stop (bool) – Whether fail-fast conditions have been triggered.
executed_count (int) – Number of scenarios actually executed.
skipped_count (int) – Number of scenarios skipped by fail-fast.
priority_map (dict[str, int]) – Maps scenario key to resolved priority.
feature_map (dict[str, str]) – Maps scenario key to parent feature name.
rule_tag_map (dict[str, list[str]]) – Maps scenario key to parent rule tags (Gherkin v6).
feature_tag_map (dict[str, list[str]]) – Maps scenario key to parent feature tags.
The PriorityState dataclass holds all mutable
execution state that persists across hooks via context._priority_state.
Note
This state is not shared across processes. When behave runs with
--parallel, each worker process gets its own isolated
PriorityState. Fail-fast, counters, and reports are per-process
and not coordinated across workers.
State Fields¶
Field |
Type |
Description |
|---|---|---|
|
|
The priority configuration for this run. |
|
|
The execution report collector. |
|
|
The sorter instance used to reorder scenarios. |
|
|
Number of failed scenarios so far. |
|
|
Whether any critical scenario has failed. |
|
|
Whether fail-fast conditions have been triggered. |
|
|
Number of scenarios actually executed (excludes skipped). |
|
|
Number of scenarios skipped by fail-fast. |
|
|
Maps scenario key to resolved priority. |
|
|
Maps scenario key to parent feature name. |
|
|
Maps scenario key to parent rule tags (Gherkin v6). |
Fail-Fast Logic¶
The check_fail_fast method evaluates two conditions:
stop_after_failures: If
failed_count >= stop_after_failures, returnsTrue.stop_on_critical: If
stop_on_criticalis enabled andcritical_failedisTrue, returnsTrue.
If either condition is met, should_stop is set to True and all
subsequent scenarios are skipped via before_scenario_hook.
Scenario Key Generation¶
The internal _scenario_key function builds a deterministic key for each
scenario:
If the scenario has
filenameandlineattributes (as behave provides), the key is"{filename}:{line}".Otherwise, falls back to
"id:{id(scenario)}".
This key is used to look up priority, feature name, and rule tags in the state maps.
Hook Lifecycle¶
before_all(context)
└─ setup_priority(context, ...)
├─ Create PriorityConfig
├─ Access runner.features
├─ Sort features & scenarios
├─ Populate priority_map, feature_map, rule_tag_map
└─ Store PriorityState in context._priority_state
before_scenario(context, scenario)
└─ before_scenario_hook(context, scenario)
└─ If should_stop: scenario.skip("fail-fast triggered")
after_scenario(context, scenario)
└─ after_scenario_hook(context, scenario)
├─ Record scenario in report
├─ If skipped: update should_stop, return
├─ Increment executed_count
├─ If failed: increment failed_count, check critical
└─ Update should_stop
after_all(context)
└─ priority_report(context)
└─ If config.report: print report
Integration Example¶
from behave_priority import (
setup_priority,
before_scenario_hook,
after_scenario_hook,
priority_report,
get_report,
)
def before_all(context):
setup_priority(
context,
order=True,
stop_after_failures=3,
stop_on_critical=True,
report=True,
)
def before_scenario(context, scenario):
before_scenario_hook(context, scenario)
def after_scenario(context, scenario):
after_scenario_hook(context, scenario)
def after_all(context):
priority_report(context)
# Optionally access the report programmatically:
report = get_report(context)
if report:
data = report.to_dict()
print(f"Pass rate: {data['summary']['pass_rate']:.1f}%")
Programmatic Report Access¶
Use get_report() to access the
PriorityReport object after a run, without
accessing context._priority_state directly:
from behave_priority import get_report
def after_all(context):
report = get_report(context)
if report:
summary = report.summary()
print(f"Executed: {summary.passed} passed, {summary.failed} failed")
print(f"Time saved: {summary.time_saved:.2f}s")