Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/390.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fall back to the default delay and backoff factor with a warning when configured values are NaN or positive infinity, preventing internal errors during reruns.
11 changes: 11 additions & 0 deletions src/pytest_rerunfailures.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import hashlib
import importlib.metadata
import inspect
import math
import os
import platform
import re
Expand Down Expand Up @@ -340,6 +341,11 @@ def get_reruns_delay(item):
warnings.warn(
"Delay time between re-runs cannot be < 0. Using default value: 0"
)
elif not math.isfinite(delay):
delay = 0
warnings.warn(
"Delay time between re-runs must be finite. Using default value: 0"
)

return delay

Expand Down Expand Up @@ -370,6 +376,11 @@ def get_reruns_delay_backoff_factor(item):
warnings.warn(
"Rerun delay backoff factor cannot be < 0. Using default value: 1.0"
)
elif not math.isfinite(factor):
factor = 1.0
warnings.warn(
"Rerun delay backoff factor must be finite. Using default value: 1.0"
)

return factor

Expand Down
46 changes: 46 additions & 0 deletions tests/test_pytest_rerunfailures.py
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,52 @@ def test_fail_two():
assert_outcomes(result, passed=0, failed=1, rerun=2)


@pytest.mark.parametrize("value", ["nan", "inf"])
@pytest.mark.parametrize("source", ["cli", "ini", "marker", "positional_marker"])
@pytest.mark.parametrize(
("setting", "warning"),
[
(
"reruns_delay",
"Delay time between re-runs must be finite. Using default value: 0",
),
(
"reruns_delay_backoff_factor",
"Rerun delay backoff factor must be finite. Using default value: 1.0",
),
],
)
def test_reruns_with_nonfinite_delay(testdir, setting, warning, source, value):
args = ["--reruns", "2"]
marker = ""
if source == "cli":
args.append(f"--{setting.replace('_', '-')}={value}")
elif source == "ini":
testdir.makeini(f"[pytest]\n{setting} = {value}")
elif source == "marker":
marker = f"@pytest.mark.flaky(reruns=2, {setting}=float({value!r}))"
elif setting == "reruns_delay":
marker = f"@pytest.mark.flaky(2, float({value!r}))"
else:
marker = f"@pytest.mark.flaky(2, 0, float({value!r}))"

testdir.makepyfile(
f"""
import pytest

{marker}
def test_recovery(request):
assert request.node.execution_count == 3
"""
)

result = testdir.runpytest(*args)

assert result.ret == pytest.ExitCode.OK
assert_outcomes(result, passed=1, rerun=2)
result.stdout.fnmatch_lines(f"*UserWarning: {warning}")


def test_reruns_with_delay_backoff_factor(testdir):
testdir.makepyfile(
"""
Expand Down