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/342.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix a regression in version 16.5 which made ``--pdb`` unusable even when no reruns were configured.
35 changes: 21 additions & 14 deletions src/pytest_rerunfailures.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,17 @@ def pytest_addoption(parser):
)


def _get_global_reruns(config):
reruns = config.getvalue("reruns")
if reruns is not None:
return reruns

reruns = None

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand this line. The check in L173 should ensure that reruns is None.

It seems that .getvalue() is deprecated anyhow https://github.com/pytest-dev/pytest/blob/68308aa288e00ff84880572ed9b3590f6cd7d470/src/_pytest/config/__init__.py#L2096 and the recommended .getoption() actually allows to set a default value which could be None here. https://github.com/pytest-dev/pytest/blob/68308aa288e00ff84880572ed9b3590f6cd7d470/src/_pytest/config/__init__.py#L2071

with suppress(TypeError, ValueError):
reruns = int(config.getini("reruns"))
return reruns


# making sure the options make sense
# should run before / at the beginning of pytest_cmdline_main
def check_options(config):
Expand All @@ -177,7 +188,8 @@ def check_options(config):
and config.option.max_suite_reruns < 0
):
raise pytest.UsageError("--max-suite-reruns must be >= 0")
if not val("collectonly") and config.option.reruns != 0:
reruns = config.getvalue("force_reruns") or _get_global_reruns(config)
if not val("collectonly") and reruns:
if config.option.usepdb: # a core option
raise pytest.UsageError("--reruns incompatible with --pdb")

Expand All @@ -186,17 +198,6 @@ def _get_marker(item):
return item.get_closest_marker("flaky")


def _get_global_reruns(item):
reruns = item.session.config.getvalue("reruns")
if reruns is not None:
return reruns

reruns = None
with suppress(TypeError, ValueError):
reruns = int(item.session.config.getini("reruns"))
return reruns


def get_reruns_count(item):
reruns = item.session.config.getvalue("force_reruns")
if reruns is not None:
Expand All @@ -215,12 +216,12 @@ def get_reruns_count(item):
marker_reruns = 1

if item.session.config.getvalue("reruns_mode") == "append":
global_reruns = _get_global_reruns(item)
global_reruns = _get_global_reruns(item.session.config)
if global_reruns is not None:
return marker_reruns + global_reruns
return marker_reruns

return _get_global_reruns(item)
return _get_global_reruns(item.session.config)


def get_reruns_delay(item):
Expand Down Expand Up @@ -924,6 +925,12 @@ def pytest_runtest_protocol(item, nextitem):
# flaky
return

if reruns and item.session.config.option.usepdb:
# the global options are already rejected in check_options(); this
# catches reruns requested via the flaky marker, which are only
# known once the item is available
raise pytest.UsageError("--reruns incompatible with --pdb")

delay = get_reruns_delay(item)
delay_backoff_factor = get_reruns_delay_backoff_factor(item)
parallel = not is_master(item.config)
Expand Down
38 changes: 38 additions & 0 deletions tests/test_pytest_rerunfailures.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,44 @@ def test_error_when_run_with_pdb(testdir):
result.stderr.fnmatch_lines_random("ERROR: --reruns incompatible with --pdb")


def test_no_error_when_run_with_pdb_without_reruns(testdir):
testdir.makepyfile("def test_pass(): pass")
result = testdir.runpytest("--pdb")
assert_outcomes(result)


def test_no_error_when_run_with_pdb_and_zero_reruns(testdir):
testdir.makepyfile("def test_pass(): pass")
result = testdir.runpytest("--reruns", "0", "--pdb")
assert_outcomes(result)


def test_error_when_run_with_pdb_and_reruns_ini(testdir):
testdir.makepyfile("def test_pass(): pass")
testdir.makeini("[pytest]\nreruns = 1\n")
result = testdir.runpytest("--pdb")
result.stderr.fnmatch_lines_random("ERROR: --reruns incompatible with --pdb")


def test_error_when_run_with_pdb_and_force_reruns(testdir):
testdir.makepyfile("def test_pass(): pass")
result = testdir.runpytest("--force-reruns", "1", "--pdb")
result.stderr.fnmatch_lines_random("ERROR: --reruns incompatible with --pdb")


def test_error_when_run_with_pdb_and_flaky_marker(testdir):
testdir.makepyfile(
"""
import pytest

@pytest.mark.flaky(reruns=1)
def test_pass(): pass
"""
)
result = testdir.runpytest("--pdb")
result.stderr.fnmatch_lines_random("*--reruns incompatible with --pdb")


def test_no_rerun_on_pass(testdir):
testdir.makepyfile("def test_pass(): pass")
result = testdir.runpytest("--reruns", "1")
Expand Down
Loading