Configuration¶
setup_retry parameters¶
setup_retry is the main entry point. It creates a RetryConfig and patches Scenario.run.
setup_retry(
context,
max_retries=3,
retry_tags=["@flaky"],
retry_on=[AssertionError, "TimeoutError"],
retry_delay=2.0,
backoff_factor=2.0,
on_retry=on_retry_callback,
max_total_retries=20,
)
Parameter reference¶
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
Behave context object (required) |
|
|
|
Maximum retries per scenario (0 = no retry) |
|
|
|
Only retry scenarios with these tags (empty = retry all) |
|
|
|
Only retry on these exception types or names (empty = retry on any) |
|
|
|
Seconds to wait before each retry (0 = no delay) |
|
|
|
Multiplier applied to |
|
|
|
Callback invoked before each retry with |
|
|
|
Global budget for total retries across all scenarios (None = unlimited) |
RetryConfig¶
The core configuration dataclass. It is frozen (immutable) and validated on creation. You can also construct it directly:
from behave_retry import RetryConfig
config = RetryConfig(
max_retries=3,
retry_tags=["@flaky"],
retry_on=[AssertionError, "TimeoutError"],
retry_delay=2.0,
backoff_factor=2.0,
max_total_retries=20,
)
Methods¶
Method |
Returns |
Description |
|---|---|---|
|
|
Check if scenario tags allow retry |
|
|
Check if exception type allows retry |
|
|
Get max retries, checking |
|
|
Calculate delay for a given retry attempt (1-based) |
Validation¶
RetryConfig raises ValueError on invalid inputs:
Condition |
Error message |
|---|---|
|
|
|
|
|
|
|
|
from behave_retry import RetryConfig
RetryConfig(max_retries=-1) # raises ValueError
RetryConfig(retry_delay=-1.0) # raises ValueError
RetryConfig(backoff_factor=0.5) # raises ValueError
RetryConfig(max_total_retries=-5) # raises ValueError
Since RetryConfig is frozen, attempting to modify an attribute raises AttributeError:
config = RetryConfig(max_retries=3)
config.max_retries = 5 # raises AttributeError
Tag override precedence¶
The @retry:N tag is resolved in this order:
Scenario-level
@retry:Ntag — highest priorityFeature-level
@retry:Ntag — fallback if scenario has noneGlobal
max_retriesfromRetryConfig— default
@retry:3 ← Feature-level
Feature: Example
Scenario: A ← No @retry tag → inherits 3 from Feature
@retry:5
Scenario: B ← Scenario-level @retry:5 → overrides to 5
@retry:0
Scenario: C ← Scenario-level @retry:0 → disables retry
Negative values from tags are clamped to 0:
@retry:-5
Scenario: X # clamped to 0, no retry
The first valid @retry:N tag wins. Subsequent @retry:N tags on the same scenario are ignored:
@retry:3
@retry:5
Scenario: X # retry:3 wins, retry:5 is ignored
Exception filter resolution¶
String entries in retry_on are resolved to exception classes on first use and cached for subsequent calls:
Bare names (
"AssertionError") — looked up inbuiltinsDotted paths (
"mymod.MyError") — split into module path and class name, imported viaimportlib
# These are equivalent:
retry_on=[AssertionError]
retry_on=["AssertionError"]
# Dotted path for custom exceptions:
retry_on=["requests.exceptions.ConnectionError"]
Exception matching¶
Matching uses issubclass, so subclasses of the listed exceptions also match:
class MyTimeoutError(TimeoutError):
...
# MyTimeoutError matches because it's a subclass of TimeoutError
setup_retry(context, retry_on=[TimeoutError])
Error handling¶
If a string cannot be resolved to an exception class,
ImportErroris raised on first use (not at config time).If an entry is neither a class nor a string,
TypeErroris raised.
Retry delay calculation¶
The delay for attempt N is:
delay = retry_delay * (backoff_factor ** (attempt - 1))
Attempt |
|
|
|
|---|---|---|---|
1 |
2.0s |
1.0s |
0.5s |
2 |
4.0s |
1.0s |
0.75s |
3 |
8.0s |
1.0s |
1.125s |
4 |
16.0s |
1.0s |
1.6875s |
If retry_delay=0.0, all delays are 0.0 regardless of backoff_factor.
Python version¶
behave-retry requires Python 3.11+.
Dependencies¶
Zero required dependencies. behave is only needed as a dev dependency for running tests.
Type checking¶
behave-retry ships with a py.typed marker (since v1.8.0), enabling type checkers like mypy and pyright to recognize type information:
from behave_retry import RetryConfig, RetryStats
config: RetryConfig = RetryConfig(max_retries=3)
# mypy knows the type of config.max_retries is int