Skip to content

Commit d2a9a59

Browse files
authored
Merge pull request #4677 from ianhi/slow-shrink-seed
Print the seed when shrinking is slow
2 parents c1d70b8 + 1d6046a commit d2a9a59

4 files changed

Lines changed: 67 additions & 11 deletions

File tree

hypothesis-python/RELEASE.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
RELEASE_TYPE: patch
2+
3+
When shrinking takes more than five minutes, Hypothesis now prints the
4+
``@seed`` decorator alongside the slow-shrinking warning so you can
5+
reproduce the failure.
6+
7+
Thanks to Ian Hunt-Isaak for this contribution!

hypothesis-python/src/hypothesis/core.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2217,19 +2217,37 @@ def wrapped_test(*arguments, **kwargs):
22172217
generated_seed = (
22182218
wrapped_test._hypothesis_internal_use_generated_seed
22192219
)
2220+
assert state._runner is not None
2221+
stopped_because_slow_shrinking = (
2222+
state._runner.statistics.get("stopped-because")
2223+
== "shrinking was very slow"
2224+
)
22202225
with local_settings(settings):
2221-
if not (state.failed_normally or generated_seed is None):
2222-
if running_under_pytest:
2223-
report(
2224-
f"You can add @seed({generated_seed}) to this test or "
2225-
f"run pytest with --hypothesis-seed={generated_seed} "
2226-
"to reproduce this failure."
2226+
if generated_seed is not None and (
2227+
not state.failed_normally or stopped_because_slow_shrinking
2228+
):
2229+
pytest_extra_msg = (
2230+
(
2231+
", or by running pytest with "
2232+
f"--hypothesis-seed={generated_seed}"
2233+
)
2234+
if running_under_pytest
2235+
else ""
2236+
)
2237+
if stopped_because_slow_shrinking:
2238+
msg = (
2239+
"\nThis test function exited early because"
2240+
" it took too long to shrink. If desired for debugging, "
2241+
f"you can reproduce this by adding @seed({generated_seed}) "
2242+
f"to this test{pytest_extra_msg}."
22272243
)
22282244
else:
2229-
report(
2230-
f"You can add @seed({generated_seed}) to this test to "
2231-
"reproduce this failure."
2245+
msg = (
2246+
"You can reproduce this failure by adding "
2247+
f"@seed({generated_seed}) to this test"
2248+
f"{pytest_extra_msg}."
22322249
)
2250+
report(msg)
22332251
# The dance here is to avoid showing users long tracebacks
22342252
# full of Hypothesis internals they don't care about.
22352253
# We have to do this inline, to avoid adding another

hypothesis-python/src/hypothesis/internal/conjecture/engine.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ def _backend_cannot_proceed(
723723
"WARNING: Hypothesis has spent more than five minutes working to shrink"
724724
" a failing example, and stopped because it is making very slow"
725725
" progress. When you re-run your tests, shrinking will resume and may"
726-
" take this long before aborting again.\nPLEASE REPORT THIS if you can"
726+
" take this long before aborting again.\n\nPLEASE REPORT THIS if you can"
727727
" provide a reproducing example, so that we can improve shrinking"
728728
" performance for everyone."
729729
)

hypothesis-python/tests/cover/test_seed_printing.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,15 @@
1212

1313
import pytest
1414

15-
from hypothesis import Verbosity, assume, core, given, settings, strategies as st
15+
from hypothesis import (
16+
HealthCheck,
17+
Verbosity,
18+
assume,
19+
core,
20+
given,
21+
settings,
22+
strategies as st,
23+
)
1624
from hypothesis.database import InMemoryExampleDatabase
1725
from hypothesis.errors import FailedHealthCheck
1826

@@ -108,3 +116,26 @@ def test(i):
108116
test()
109117

110118
assert "@seed" in o.getvalue()
119+
120+
121+
@pytest.mark.parametrize("in_pytest", [True, False])
122+
def test_prints_seed_on_very_slow_shrinking(monkeypatch, in_pytest):
123+
monkeypatch.setattr(core, "running_under_pytest", in_pytest)
124+
125+
@settings(database=None, deadline=None, suppress_health_check=list(HealthCheck))
126+
@given(st.integers(min_value=0, max_value=2**64 - 1))
127+
def test(n):
128+
time.sleep(10)
129+
assert n <= 2**33
130+
131+
with capture_out() as o, pytest.raises(AssertionError):
132+
test()
133+
134+
output = o.getvalue()
135+
assert "Hypothesis has spent more than five minutes" in output
136+
assert (
137+
"This test function exited early because it took too long to shrink" in output
138+
)
139+
seed = test._hypothesis_internal_use_generated_seed
140+
assert output.count(f"@seed({seed})") == 1
141+
assert (f"--hypothesis-seed={seed}" in output) == in_pytest

0 commit comments

Comments
 (0)