Skip to content

Commit

Permalink
recommend remedies in unsatsisfiable
Browse files Browse the repository at this point in the history
  • Loading branch information
tybug committed Dec 7, 2024
1 parent 248a0c1 commit 54777d6
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 2 deletions.
27 changes: 26 additions & 1 deletion hypothesis-python/src/hypothesis/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1231,8 +1231,33 @@ def run_engine(self):
)
else:
if runner.valid_examples == 0:
explanations = []
# use a somewhat arbitrary cutoff to avoid recommending spurious
# fixes.
# eg, a few invalid examples from internal filters when the
# problem is the user generating large inputs, or a
# few overruns during internal mutation when the problem is
# impossible user filters/assumes.
if runner.invalid_examples > min(20, runner.call_count // 5):
explanations.append(
f"{runner.invalid_examples} of {runner.call_count} "
"examples failed a .filter() or assume() condition. Try "
"making your filters or assumes less strict, or rewrite "
"using strategy parameters: "
"st.integers().filter(lambda x: x > 0) fails less often "
"(that is, never) when rewritten as st.integers(min_value=1)."
)
if runner.overrun_examples > min(20, runner.call_count // 5):
explanations.append(
f"{runner.overrun_examples} of {runner.call_count} "
"examples were too large to finish generating. Try "
"reducing the size of your inputs."
)
rep = get_pretty_function_description(self.test)
raise Unsatisfiable(f"Unable to satisfy assumptions of {rep}")
raise Unsatisfiable(
f"Unable to satisfy assumptions of {rep}. "
f"{' Also, '.join(explanations)}"
)

# If we have not traced executions, warn about that now (but only when
# we'd expect to do so reliably, i.e. on CPython>=3.12)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ def __init__(
self.call_count: int = 0
self.misaligned_count: int = 0
self.valid_examples: int = 0
self.invalid_examples = 0
self.overrun_examples = 0
self.random: Random = random or Random(getrandbits(128))
self.database_key: Optional[bytes] = database_key
self.ignore_limits: bool = ignore_limits
Expand Down Expand Up @@ -567,8 +569,12 @@ def test_function(self, data: ConjectureData) -> None:
assert not isinstance(data_as_result, _Overrun)
self.best_examples_of_observed_targets[k] = data_as_result

if data.status == Status.VALID:
if data.status is Status.VALID:
self.valid_examples += 1
if data.status is Status.INVALID:
self.invalid_examples += 1
if data.status is Status.OVERRUN:
self.overrun_examples += 1

if data.status == Status.INTERESTING:
if not self.using_hypothesis_backend:
Expand Down

0 comments on commit 54777d6

Please sign in to comment.