diff --git a/hypothesis-python/RELEASE.rst b/hypothesis-python/RELEASE.rst new file mode 100644 index 00000000000..7aa8dd25fab --- /dev/null +++ b/hypothesis-python/RELEASE.rst @@ -0,0 +1,5 @@ +RELEASE_TYPE: patch + +If multiple explicit examples (from :func:`@example() `) +raise a Skip exception, for consistency with generated examples we now re-raise +the first instead of collecting them into an ExceptionGroup (:issue:`3453`). diff --git a/hypothesis-python/src/hypothesis/core.py b/hypothesis-python/src/hypothesis/core.py index 87af19d789a..80ff8d30631 100644 --- a/hypothesis-python/src/hypothesis/core.py +++ b/hypothesis-python/src/hypothesis/core.py @@ -437,7 +437,11 @@ def execute_explicit_examples(state, wrapped_test, arguments, kwargs, original_s err = new yield (fragments_reported, err) - if state.settings.report_multiple_bugs and pytest_shows_exceptiongroups: + if ( + state.settings.report_multiple_bugs + and pytest_shows_exceptiongroups + and not isinstance(err, skip_exceptions_to_reraise()) + ): continue break finally: @@ -1192,6 +1196,13 @@ def wrapped_test(*arguments, **kwargs): # If we're not going to report multiple bugs, we would have # stopped running explicit examples at the first failure. assert len(errors) == 1 or state.settings.report_multiple_bugs + + # If an explicit example raised a 'skip' exception, ensure it's never + # wrapped up in an exception group. Because we break out of the loop + # immediately on finding a skip, if present it's always the last error. + if isinstance(errors[-1][1], skip_exceptions_to_reraise()): + del errors[:-1] + _raise_to_user(errors, state.settings, [], " in explicit examples") # If there were any explicit examples, they all ran successfully. diff --git a/hypothesis-python/tests/pytest/test_skipping.py b/hypothesis-python/tests/pytest/test_skipping.py index 0433fe97069..4e504837fe2 100644 --- a/hypothesis-python/tests/pytest/test_skipping.py +++ b/hypothesis-python/tests/pytest/test_skipping.py @@ -39,3 +39,25 @@ def test_no_falsifying_example_if_pytest_skip(testdir): ) out = "\n".join(result.stdout.lines) assert "Falsifying example" not in out + + +def test_issue_3453_regression(testdir): + """If ``pytest.skip() is called during a test, Hypothesis should not + continue running the test and shrink process, nor should it print anything + about falsifying examples.""" + script = testdir.makepyfile( + """ +from hypothesis import example, given, strategies as st +import pytest + +@given(value=st.none()) +@example("hello") +@example("goodbye") +def test_skip_on_first_skipping_example(value): + assert value is not None + assert value != "hello" # queue up a non-skip error which must be discarded + pytest.skip() +""" + ) + result = testdir.runpytest(script, "--tb=native", "-s") + result.assert_outcomes(skipped=1)