Changelog¶
All notable changes to this project will be documented in this file.
[1.8.2] - 2026-07-13¶
Added¶
Sphinx documentation site with Furo theme deployed to GitHub Pages
17 documentation pages: installation, quickstart, features, configuration, examples, how it works, API reference
GitHub Actions workflow for automatic docs deployment
docsoptional dependency group in pyproject.tomlDocumentation URL in pyproject.toml project urls
Fixed¶
max_total_retriesbudget exhaustion no longer records stats on first attempt (attempt=1) — consistent with retry_on filter pathRemoved unused
_get_scenario_statusdead code from hooks.py
Changed¶
README.md simplified with comparison table, how it works summary, and documentation links
Coverage badge updated to 100%
[1.8.1] - 2026-07-13¶
Added¶
32 new edge case tests achieving 100% coverage across all modules
Tests for
_resolve_exception_filterand_import_exceptionerror paths (TypeError, ImportError)Tests for
_reset_scenario_statewithstep.reset(),exception,error_messageattrsTests for
_patch_scenario_runImportError fallbackTests for
retry_onfilter recording stats after retryTests for
parse_retry_tagedge cases (empty, no colon, negative, duplicates, None)Tests for
get_retry_delaywith attempt 0, negative, and large valuesTests for
should_retry_tagwith@prefix normalization
Fixed¶
mypy type errors resolved (
import-untyped,RetryStats | None,attr-defined)
[1.8.0] - 2026-07-13¶
Fixed¶
_get_scenario_keynow includes scenario name in the key (filename:line:name) to prevent collisions between Scenario Outline examples that share the same filename and line but have different names after placeholder substitution
Added¶
4 new tests for Scenario Outline key uniqueness and independent retry behavior
[1.7.0] - 2026-07-13¶
Added¶
Logging integration via
logging.getLogger("behave_retry")— logs config onsetup_retry, each retry with scenario name/attempt/exception type, and summary onretry_report6 new tests for logging behavior using
caplog(config log, retry log with name/attempt, exception type, no log on pass, summary log, no log when not configured)
[1.6.0] - 2026-07-13¶
Added¶
max_total_retriesparameter inRetryConfigandsetup_retry— global budget for total retries across all scenarios_behave_retry_totalcounter tracked in context bypatched_runValidation for
max_total_retries(must be >= 0 or None) inRetryConfig.__post_init__9 new tests: 3 for config validation, 6 for budget behavior (exhausted, unlimited, zero, shared, not consumed on pass, stored in config)
[1.5.0] - 2026-07-13¶
Added¶
Feature-level
@retry:Ntag support — scenarios inherit retry count from their parent Feature tag when they don’t have their own@retry:N_get_feature_tagshelper inhooks.pyto extract tags from the parent Featureget_scenario_retriesnow accepts an optionalfeature_tagsparameter for fallback resolutionshould_retry_tagnow considers both scenario and feature tags for filtering13 new tests: 8 for
get_scenario_retrieswith feature tags, 5 for_get_feature_tagshelper and feature tag inheritance inpatched_run
[1.4.0] - 2026-07-13¶
Added¶
on_retrycallback parameter inRetryConfigandsetup_retry— invoked before each retry with(context, scenario, attempt, exception)RetryCallbacktype alias exported from the package_get_last_exceptionhelper to retrieve the exception instance from a failed scenario8 new tests for
on_retrycallback behavior (called on retry, each retry, not called without callback, not called on pass, None exception, called before delay, stored in config)retry_onnow accepts string exception names in addition to classes — e.g.["AssertionError", "json.JSONDecodeError"]ExceptionFiltertype alias exported from the package_resolve_exception_filterand_import_exceptionhelpers for resolving string names to exception classes with caching8 new tests for string-based exception filtering (builtin match, builtin no-match, dotted path, mixed class+string, invalid builtin, invalid module, cache verification)
[1.3.0] - 2026-07-13¶
Added¶
py.typedmarker file for PEP 561 type-checker supportforce-includeinpyproject.tomlto ensurepy.typedis packaged in the wheelretry_delayandbackoff_factorparameters toRetryConfigandsetup_retry— configurable delay between retries with exponential backoffRetryConfig.get_retry_delay(attempt)method — calculates the delay for a given retry attempt numberValidation for
retry_delay(must be >= 0) andbackoff_factor(must be >= 1.0) inRetryConfig.__post_init__10 new tests: 6 for
get_retry_delay(zero, fixed, backoff, fractional, large factor, zero-with-backoff), 4 forpatched_rundelay behavior (no-delay, fixed, backoff, delay-only-before-retry)
[1.2.0] - 2026-07-13¶
Added¶
Google-style docstrings (
Args,Returns,Raises,Attributes) on all public and internal functions, methods, properties, and classespatched_runinner function now has a full docstring__post_init__now has a docstring withRaisessectionscenarios_passed_on_retryandscenarios_failed_after_retryproperties now have docstringsTest:
test_tag_with_double_at_prefix_not_parsed— verifies@@retry:3is rejectedTest:
test_reset_scenario_state_no_clear_status— verifies fallback when scenario lacksclear_status()Test:
test_patched_run_without_config_falls_back— verifies graceful degradation when context loses configTest:
test_patched_run_without_stats_falls_back— verifies graceful degradation when context loses statsTest:
test_negative_tag_clamped_to_zero— verifies negative@retry:Ntags are clamped to 0Test:
test_setup_retry_updates_config_after_repatch— verifies re-callingsetup_retrywith new config takes effectTest:
test_flaky_value_error_retried— integration test forValueErrorwithStatus.errorIntegration feature:
Flaky ValueError scenario that passes on 2nd attemptfor error-status retry testing
Fixed¶
lstrip("@")replaced withremoveprefix("@")inparse_retry_tagandshould_retry_tag—lstripstripped all leading@characters, so@@retry:3was incorrectly parsed as valid_reset_scenario_statenow guardsclear_status()withhasattr— falls back toscenario.status = Noneinstead of crashing withAttributeErrorpatched_runnow readsconfigandstatsfromcontextat runtime viagetattrinstead of capturing them in the closure — prevents stale references whensetup_retryis called multiple timespatched_rungracefully delegates tooriginal_runif_behave_retry_configor_behave_retry_statsare missing from contextNegative
@retry:Ntag values are now clamped to 0 viamax(0, override)inget_scenario_retries_step_failedhelper now detects both"failed"and"error"step statuses — Behave assignsStatus.errorto non-AssertionErrorexceptionsafter_scenario_hookusesgetattrfor_behave_retry_attempts— preventsAttributeErrorif attribute is missingPatch idempotency:
patched_runis marked with_behave_retry_patched = Trueto prevent double-wrappingScenario.runon repeatedsetup_retrycallsValueErroradded toretry_onin filtering integration tests to testStatus.errorhandling end-to-end
Changed¶
RetryStats.update_retrycalculatesmatch_keyoutside the loop for minor performance improvementRemoved dead code:
_should_retry_scenariofunction andreset_attemptsinflaky_steps.pyRenamed
test_value_error_not_retriedtotest_value_error_fails_without_flaky_tagfor clarityUpdated
test_all_filtering_featureassertions to reflect new scenario countsUpdated
test_matching_tag_retriesto expect 2 passed scenarios (both@flakytags)
[1.1.0] - 2026-07-13¶
Added¶
Real retry:
setup_retrynow patchesbehave.model.Scenario.runto re-execute failed scenarios automaticallyparse_retry_tagmoved toconfig.pyand unified withget_scenario_retries— single source of truth for@retry:Nparsingparse_retry_tagexported from top-level package
Fixed¶
_get_scenario_keyno longer usesFeatureobject as fallback — only usesfilename(string) or scenario namepyproject.tomldescription no longer mentions non-existent CLI flagsafter_scenario_hookdocstring no longer references non-existent CLI flagsREADME example output fixed: scenarios with 1 attempt are not “retried”
Changed¶
after_scenario_hookis now backward-compatible — the retry loop is handled by the patchedScenario.run, the hook only tracks attemptsVersion bumped to 1.1.0 (minor: new feature — real retry)
[1.0.2] - 2026-07-13¶
Fixed¶
Scenario collision fixed — uses
filename:lineas unique key instead of nameparse_retry_tagnow delegates toRetryConfig.get_scenario_retriesto avoid duplicated logic
Changed¶
RetryConfigis now a frozen dataclass (immutable)max_retriesvalidation: raisesValueErrorif negativeRemoved unused
RetryExhaustedErrorexception andexceptions.pymoduleREADME and CHANGELOG corrected: removed references to non-existent CLI flags and
after_retryhook
Added¶
RetryStats.to_dict()andScenarioRetry.to_dict()for CI/CD reporting__repr__onRetryStatsandScenarioRetry(via dataclass)
[1.0.1] - 2026-07-13¶
Fixed¶
Exception filtering (
retry_on) now actually works —should_retry_exceptionis called inafter_scenario_hookStats no longer duplicate entries per attempt —
update_retryupdates a single record per scenariototal_retriescorrectly counts retries (attempts - 1) instead of inflating with duplicate entriesException type names are now captured from failed steps instead of always being empty
Removed broken
_get_last_exception()functionRemoved dead code in
_get_scenario_tags()(loop withpassbody)
Added¶
RetryStats.update_retry()— update an existing retry record or create a new one_get_step_status(),_get_scenario_exceptions(),_get_last_exception_type()helper functions9 new tests covering exception filtering, stats deduplication, and step exception capture
[1.0.0] - 2026-07-13¶
Added¶
setup_retry()— configure retry inbefore_allhookafter_scenario_hook()— handle retry logic inafter_scenarioretry_report()— human-readable retry summaryRetryStatsandScenarioRetrydataclasses for stats trackingRetryConfigdataclass for configuration@retry:Ntag per scenario for override@retry:0tag to disable retry for a scenarioZero required dependencies