Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

events for more mark_invalid() cases #3654

Merged
merged 5 commits into from
May 26, 2023
Merged
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 AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ their individual contributions.
* `Bryant Eisenbach <https://github.com/fubuloubu>`_
* `Buck Evan, copyright Google LLC <https://github.com/bukzor>`_
* `Cameron McGill <https://www.github.com/Cameron-JM>`_
* `Carl Meyer <https://www.github.com/carljm>`_
* `Charles O'Farrell <https://www.github.com/charleso>`_
* `Charlie Tanksley <https://www.github.com/charlietanksley>`_
* `Chase Garner <https://www.github.com/chasegarner>`_ (chase@garner.red)
Expand Down
4 changes: 4 additions & 0 deletions hypothesis-python/RELEASE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
RELEASE_TYPE: patch

Hypothesis will now record an event for more cases where data is marked
invalid, including for exceeding the internal depth limit.
15 changes: 9 additions & 6 deletions hypothesis-python/src/hypothesis/internal/conjecture/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
Iterable,
Iterator,
List,
NoReturn,
Optional,
Sequence,
Set,
Expand Down Expand Up @@ -936,10 +937,10 @@ def draw(self, strategy: "SearchStrategy[Ex]", label: Optional[int] = None) -> "
strategy.validate()

if strategy.is_empty:
self.mark_invalid()
self.mark_invalid("strategy is empty")

if self.depth >= MAX_DEPTH:
self.mark_invalid()
self.mark_invalid("max depth exceeded")

if label is None:
assert isinstance(strategy.label, int)
Expand Down Expand Up @@ -1119,7 +1120,7 @@ def conclude_test(
self,
status: Status,
interesting_origin: Optional[InterestingOrigin] = None,
) -> None:
) -> NoReturn:
assert (interesting_origin is None) or (status == Status.INTERESTING)
self.__assert_not_frozen("conclude_test")
self.interesting_origin = interesting_origin
Expand All @@ -1129,13 +1130,15 @@ def conclude_test(

def mark_interesting(
self, interesting_origin: Optional[InterestingOrigin] = None
) -> None:
) -> NoReturn:
self.conclude_test(Status.INTERESTING, interesting_origin)

def mark_invalid(self):
def mark_invalid(self, why: Optional[str] = None) -> NoReturn:
if why is not None:
self.note_event(why)
self.conclude_test(Status.INVALID)

def mark_overrun(self):
def mark_overrun(self) -> NoReturn:
self.conclude_test(Status.OVERRUN)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ def more(self) -> bool:
self.data.stop_example()
return False

def reject(self):
def reject(self, why: Optional[str] = None) -> None:
"""Reject the last example (i.e. don't count it towards our budget of
elements because it's not going to go in the final collection)."""
assert self.count > 0
Expand All @@ -463,7 +463,7 @@ def reject(self):
# failing too fast when we reject the first draw.
if self.rejections > max(3, 2 * self.count):
if self.count < self.min_size:
self.data.mark_invalid()
self.data.mark_invalid(why)
else:
self.force_stop = True

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ def not_yet_in_unique_list(val):
while elements.more():
value = filtered.do_filtered_draw(data)
if value is filter_not_satisfied:
elements.reject()
elements.reject("Aborted test because unable to satisfy {filtered!r}")
else:
for key, seen in zip(self.keys, seen_sets):
seen.add(key(value))
Expand Down Expand Up @@ -274,7 +274,9 @@ def do_draw(self, data):
value = (value,) + data.draw(self.tuple_suffixes)
result.append(value)
else:
should_draw.reject()
should_draw.reject(
"UniqueSampledListStrategy filter not satisfied or value already seen"
)
assert self.max_size >= len(result) >= self.min_size
return result

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def do_draw(self, data):

# If we happened to end up with a disallowed imaginary time, reject it.
if (not self.allow_imaginary) and datetime_does_not_exist(result):
data.mark_invalid()
data.mark_invalid("nonexistent datetime")
return result

def draw_naive_datetime_and_combine(self, data, tz):
Expand All @@ -165,8 +165,7 @@ def draw_naive_datetime_and_combine(self, data, tz):
return replace_tzinfo(dt.datetime(**result), timezone=tz)
except (ValueError, OverflowError):
msg = "Failed to draw a datetime between %r and %r with timezone from %r."
data.note_event(msg % (self.min_value, self.max_value, self.tz_strat))
data.mark_invalid()
data.mark_invalid(msg % (self.min_value, self.max_value, self.tz_strat))


@defines_strategy(force_reusable_values=True)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -529,8 +529,7 @@ def _transform(self, element):
def do_draw(self, data):
result = self.do_filtered_draw(data)
if result is filter_not_satisfied:
data.note_event(f"Aborted test because unable to satisfy {self!r}")
data.mark_invalid()
data.mark_invalid(f"Aborted test because unable to satisfy {self!r}")
return result

def get_element(self, i):
Expand Down Expand Up @@ -944,8 +943,7 @@ def do_draw(self, data: ConjectureData) -> Ex:
if result is not filter_not_satisfied:
return result

data.note_event(f"Aborted test because unable to satisfy {self!r}")
data.mark_invalid()
data.mark_invalid(f"Aborted test because unable to satisfy {self!r}")
raise NotImplementedError("Unreachable, for Mypy")

def note_retried(self, data):
Expand Down
9 changes: 9 additions & 0 deletions hypothesis-python/tests/conjecture/test_test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,15 @@ def test_can_mark_invalid():
assert x.status == Status.INVALID


def test_can_mark_invalid_with_why():
x = ConjectureData.for_buffer(b"")
with pytest.raises(StopTest):
x.mark_invalid("some reason")
assert x.frozen
assert x.status == Status.INVALID
assert x.events == {"some reason"}


class BoomStrategy(SearchStrategy):
def do_draw(self, data):
data.draw_bytes(1)
Expand Down