Skip to content

Commit 5bffb0f

Browse files
BeyondEvilsallner
authored andcommitted
Add optional condition to marker
1 parent 0270f30 commit 5bffb0f

4 files changed

Lines changed: 71 additions & 9 deletions

File tree

CHANGES.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ Other changes
1515
- Check for the resultlog by feature and not by version as pytest master does
1616
not provide a consistent version.
1717

18+
- Add ``condition`` keyword argument to the re-run marker. (Thanks to `@BeyondEvil`_ for the PR)
19+
20+
.. _@BeyondEvil: https://github.com/BeyondEvil
1821

1922
9.1.1 (2020-09-29)
2023
------------------

README.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,17 @@ You can also specify the re-run delay time in the marker:
9999
import random
100100
assert random.choice([True, False])
101101
102+
You can also specify an optional ``condition`` in the re-run marker:
103+
104+
.. code-block:: python
105+
106+
@pytest.mark.flaky(reruns=5, condition=sys.platform.startswith("win32"))
107+
def test_example():
108+
import random
109+
assert random.choice([True, False])
110+
111+
Note that the test will re-run for any ``condition`` that is truthy.
112+
102113
Output
103114
------
104115

pytest_rerunfailures.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,16 @@ def get_reruns_delay(item):
175175
return delay
176176

177177

178+
def get_reruns_condition(item):
179+
rerun_marker = _get_marker(item)
180+
181+
condition = True
182+
if rerun_marker is not None and "condition" in rerun_marker.kwargs:
183+
condition = rerun_marker.kwargs["condition"]
184+
185+
return condition
186+
187+
178188
def _remove_cached_results_from_failed_fixtures(item):
179189
"""
180190
Note: remove all cached_result attribute from every fixture
@@ -221,6 +231,19 @@ def _should_hard_fail_on_error(session_config, report):
221231
return True
222232

223233

234+
def _should_not_rerun(item, report, reruns):
235+
xfail = hasattr(report, "wasxfail")
236+
is_terminal_error = _should_hard_fail_on_error(item.session.config, report)
237+
condition = get_reruns_condition(item)
238+
return (
239+
item.execution_count > reruns
240+
or not report.failed
241+
or xfail
242+
or is_terminal_error
243+
or not condition
244+
)
245+
246+
224247
def pytest_runtest_protocol(item, nextitem):
225248
"""
226249
Note: when teardown fails, two reports are generated for the case, one for
@@ -247,15 +270,8 @@ def pytest_runtest_protocol(item, nextitem):
247270
reports = runtestprotocol(item, nextitem=nextitem, log=False)
248271

249272
for report in reports: # 3 reports: setup, call, teardown
250-
is_terminal_error = _should_hard_fail_on_error(item.session.config, report)
251273
report.rerun = item.execution_count - 1
252-
xfail = hasattr(report, "wasxfail")
253-
if (
254-
item.execution_count > reruns
255-
or not report.failed
256-
or xfail
257-
or is_terminal_error
258-
):
274+
if _should_not_rerun(item, report, reruns):
259275
# last run or no failure detected, log normally
260276
item.ihook.pytest_runtest_logreport(report=report)
261277
else:

test_pytest_rerunfailures.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def check_outcome_field(outcomes, field_name, expected_value):
3232

3333

3434
def assert_outcomes(
35-
result, passed=1, skipped=0, failed=0, error=0, xfailed=0, xpassed=0, rerun=0,
35+
result, passed=1, skipped=0, failed=0, error=0, xfailed=0, xpassed=0, rerun=0
3636
):
3737
outcomes = result.parseoutcomes()
3838
check_outcome_field(outcomes, "passed", passed)
@@ -511,3 +511,35 @@ def test_only_rerun_flag(testdir, only_rerun_texts, should_rerun):
511511
assert_outcomes(
512512
result, passed=num_passed, failed=num_failed, rerun=num_reruns_actual
513513
)
514+
515+
516+
@pytest.mark.parametrize(
517+
"condition, expected_reruns",
518+
[
519+
(1 == 1, 2),
520+
(1 == 2, 0),
521+
(True, 2),
522+
(False, 0),
523+
(1, 2),
524+
(0, 0),
525+
("'non-empty'", 2),
526+
("''", 0),
527+
(["list"], 2),
528+
([], 0),
529+
({"dict": 1}, 2),
530+
({}, 0),
531+
(None, 0),
532+
],
533+
)
534+
def test_reruns_with_condition_marker(testdir, condition, expected_reruns):
535+
testdir.makepyfile(
536+
f"""
537+
import pytest
538+
539+
@pytest.mark.flaky(reruns=2, condition={condition})
540+
def test_fail_two():
541+
assert False"""
542+
)
543+
544+
result = testdir.runpytest()
545+
assert_outcomes(result, passed=0, failed=1, rerun=expected_reruns)

0 commit comments

Comments
 (0)