diff --git a/CHANGES.rst b/CHANGES.rst index e800065..e633378 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -25,6 +25,11 @@ Bug fixes empty before executing a fixture. Fixes `#323 `_. +- Accept exception classes (not only regex strings) in the ``only_rerun`` and + ``rerun_except`` marker keyword arguments instead of crashing with an + internal error. + Fixes `#275 `_. + 16.1 (2025-10-10) ----------------- diff --git a/README.rst b/README.rst index e4691db..9fb4c9e 100644 --- a/README.rst +++ b/README.rst @@ -173,6 +173,14 @@ Or a list of strings: def test_example(): raise AssertionError() +Exception classes are also accepted and match any subclass: + +.. code-block:: python + + @pytest.mark.flaky(only_rerun=[AssertionError, ValueError]) + def test_example(): + raise AssertionError() + You can use ``@pytest.mark.flaky(condition)`` similarly as ``@pytest.mark.skipif(condition)``, see `pytest-mark-skipif `_ diff --git a/src/pytest_rerunfailures.py b/src/pytest_rerunfailures.py index a2cceed..6afd05e 100644 --- a/src/pytest_rerunfailures.py +++ b/src/pytest_rerunfailures.py @@ -286,8 +286,11 @@ def _matches_any_rerun_except_error(rerun_except_errors, excinfo): def _try_match_error(rerun_errors, excinfo): if excinfo: err = f"{excinfo.type.__name__}: {excinfo.value}" - for rerun_regex in rerun_errors: - if re.search(rerun_regex, err): + for rerun_error in rerun_errors: + if isinstance(rerun_error, type) and issubclass(rerun_error, BaseException): + if issubclass(excinfo.type, rerun_error): + return True + elif re.search(rerun_error, err): return True return False diff --git a/tests/test_pytest_rerunfailures.py b/tests/test_pytest_rerunfailures.py index 7156bc9..1174bf2 100644 --- a/tests/test_pytest_rerunfailures.py +++ b/tests/test_pytest_rerunfailures.py @@ -820,6 +820,30 @@ def test_fail(): assert_outcomes(result, passed=0, failed=1, rerun=num_reruns) +@pytest.mark.parametrize( + "filter_kwarg,should_rerun", + [ + ("only_rerun=[AssertionError]", True), + ("only_rerun=[ValueError]", False), + ("rerun_except=[AssertionError]", False), + ("rerun_except=[ValueError]", True), + ], +) +def test_rerun_filter_accepts_exception_classes(testdir, filter_kwarg, should_rerun): + testdir.makepyfile( + f""" + import pytest + + @pytest.mark.flaky(reruns=1, {filter_kwarg}) + def test_fail(): + raise AssertionError("ERR") + """ + ) + result = testdir.runpytest() + num_reruns = 1 if should_rerun else 0 + assert_outcomes(result, passed=0, failed=1, rerun=num_reruns) + + @pytest.mark.parametrize( "marker_rerun_except,cli_rerun_except,raised_error,should_rerun", [