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(scenario)[source]
Build a deterministic key for a scenario.
Uses
filenameandlineattributes when available (as behave provides), falling back toid()for objects without them.
- behave_priority.hooks.setup_priority(context, *, order=None, reverse=None, priority_tag=None, stop_after_failures=None, stop_on_critical=None, critical_tag='critical', default_priority=999, report=None, report_format='text', parallel_coord=None)[source]¶
Set up priority execution in before_all hook.
Configuration can be passed explicitly or via environment variables when arguments are
None.- Parameters:
context (
Any) – Behave’s context object (contextinbefore_all).order (
bool|None) – Sort scenarios by priority (highest first). IfNone, readsBEHAVE_PRIORITY_ORDER(default0).reverse (
bool|None) – Reverse sort order (lowest priority first). IfNone, readsBEHAVE_PRIORITY_REVERSE(default0).priority_tag (
str|None) – Tag name to run first (e.g."smoke").stop_after_failures (
int|None) – Stop after N failed scenarios. IfNone, readsBEHAVE_PRIORITY_STOP_AFTER(default disabled).stop_on_critical (
bool|None) – Stop if any critical scenario fails. IfNone, readsBEHAVE_PRIORITY_FAIL_FAST(default0).critical_tag (
str) – Tag name that marks a scenario as critical.default_priority (
int) – Priority for scenarios without a priority tag.report (
bool|None) – Print execution report after run. IfNone, readsBEHAVE_PRIORITY_REPORT(default0).report_format (
Literal['text','json','csv']) – Output format for the report ("text","json","csv").parallel_coord (
bool|None) – Enable cross-process fail-fast coordination. IfNone, readsBEHAVE_PRIORITY_PARALLEL_COORD(default0). RequiresBEHAVE_PRIORITY_COORD_DIRenv var to be set.
- Return type:
- behave_priority.hooks.before_scenario_hook(context, scenario)[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.
- behave_priority.hooks.after_scenario_hook(context, scenario)[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.
- behave_priority.hooks.get_report(context)[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 (
Any) – Behave’s context object.- Return type:
- Returns:
The
PriorityReportif priority state was set up, otherwise None.
- behave_priority.hooks.priority_report(context)[source]¶
Print the priority execution report.
Intended for use as
after_allin behave’senvironment.py. Writes tosys.__stdout__(falling back tosys.stdout) so the report stays visible even when behave’s output capture is enabled, which is the default — behave captures stdout/stderr during hooks.
- behave_priority.hooks.cleanup_parallel_coord(context)[source]¶
Clean up the parallel coordinator for this worker.
Intended for use in
after_allalongsidepriority_report. Removes this worker’s file from the coordination directory.
PriorityState¶
- class behave_priority.hooks.PriorityState(config, report, sorter, coordinator=None, failed_count=0, critical_failed=False, should_stop=False, executed_count=0, skipped_count=0, priority_map=<factory>, feature_map=<factory>, rule_tag_map=<factory>, feature_tag_map=<factory>, missing_skip_warned=False)[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 – The priority configuration.
report – The execution report collector.
sorter – The scenario sorter instance.
coordinator – Optional parallel coordinator for cross-process fail-fast. None when
parallel_coordis disabled.failed_count – Number of failed scenarios so far.
critical_failed – Whether any critical scenario has failed.
should_stop – Whether fail-fast conditions have been triggered.
executed_count – Number of scenarios actually executed.
skipped_count – Number of scenarios skipped by fail-fast.
priority_map – Maps scenario key to resolved priority.
feature_map – Maps scenario key to parent feature name.
rule_tag_map – Maps scenario key to parent rule tags (Gherkin v6).
feature_tag_map – Maps scenario key to parent feature tags.
missing_skip_warned – Whether the missing
scenario.skip()warning has already been emitted (warned once per run).
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. |
|
|
Optional parallel coordinator for cross-process fail-fast. |
|
|
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). |
|
|
Maps scenario key to parent feature tags. |
|
|
Whether the missing |
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")