Skip to content

Commit 6c20067

Browse files
committed
fix persisting event symbolics
1 parent f2bf8a6 commit 6c20067

6 files changed

Lines changed: 43 additions & 12 deletions

File tree

hypothesis-python/RELEASE.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
RELEASE_TYPE: patch
2+
3+
Fix a bug where we persisted symbolics from solver-based :ref:`alternative backends <alternative-backends>` in |event|.

hypothesis-python/src/hypothesis/control.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -247,22 +247,34 @@ def event(value: str, payload: Union[str, int, float] = "") -> None:
247247
"""
248248
context = _current_build_context.value
249249
if context is None:
250-
raise InvalidArgument("Cannot make record events outside of a test")
250+
raise InvalidArgument("Cannot record events outside of a test")
251251

252-
payload = _event_to_string(payload, (str, int, float))
253-
context.data.events[_event_to_string(value)] = payload
252+
avoid_realization = context.data.provider.avoid_realization
253+
payload = _event_to_string(
254+
payload, allowed_types=(str, int, float), avoid_realization=avoid_realization
255+
)
256+
value = _event_to_string(value, avoid_realization=avoid_realization)
257+
context.data.events[value] = payload
254258

255259

256260
_events_to_strings: WeakKeyDictionary = WeakKeyDictionary()
257261

258262

259-
def _event_to_string(event, allowed_types=str):
263+
def _event_to_string(event, *, allowed_types=str, avoid_realization):
260264
if isinstance(event, allowed_types):
261265
return event
266+
267+
# _events_to_strings is a cache which persists across iterations, causing
268+
# problems for symbolic backends. see
269+
# https://github.com/pschanely/hypothesis-crosshair/issues/41
270+
if avoid_realization:
271+
return str(event)
272+
262273
try:
263274
return _events_to_strings[event]
264275
except (KeyError, TypeError):
265276
pass
277+
266278
result = str(event)
267279
try:
268280
_events_to_strings[event] = result

hypothesis-python/src/hypothesis/core.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,16 @@ def _execute_once_for_engine(self, data: ConjectureData) -> None:
13051305
finally:
13061306
# Conditional here so we can save some time constructing the payload; in
13071307
# other cases (without coverage) it's cheap enough to do that regardless.
1308+
#
1309+
# Note that we have to unconditionally realize data.events, because
1310+
# the statistics reported by the pytest plugin use a different flow
1311+
# than observability, but still access symbolic events.
1312+
1313+
try:
1314+
data.events = data.provider.realize(data.events)
1315+
except BackendCannotProceed:
1316+
data.events = {}
1317+
13081318
if observability_enabled():
13091319
if runner := getattr(self, "_runner", None):
13101320
phase = runner._current_phase
@@ -1329,11 +1339,6 @@ def _execute_once_for_engine(self, data: ConjectureData) -> None:
13291339
except BackendCannotProceed:
13301340
self._string_repr = "<backend failed to realize symbolic arguments>"
13311341

1332-
try:
1333-
data.events = data.provider.realize(data.events)
1334-
except BackendCannotProceed:
1335-
data.events = {}
1336-
13371342
data.freeze()
13381343
tc = make_testcase(
13391344
run_start=self._start_timestamp,

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,10 @@ def test_function(self, data: ConjectureData) -> None:
556556
if not interrupted: # pragma: no branch
557557
assert data.cannot_proceed_scope is None
558558
data.freeze()
559+
560+
if self.settings.backend != "hypothesis":
561+
realize_choices(data, for_failure=data.status is Status.INTERESTING)
562+
559563
call_stats: CallStats = {
560564
"status": data.status.name.lower(),
561565
"runtime": data.finish_time - data.start_time,
@@ -566,8 +570,6 @@ def test_function(self, data: ConjectureData) -> None:
566570
),
567571
}
568572
self.stats_per_test_case.append(call_stats)
569-
if self.settings.backend != "hypothesis":
570-
realize_choices(data, for_failure=data.status is Status.INTERESTING)
571573

572574
self._cache(data)
573575
if data.misaligned_at is not None: # pragma: no branch # coverage bug?

hypothesis-python/tests/cover/test_control.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,4 +232,5 @@ def step(self):
232232

233233

234234
def test_can_convert_non_weakref_types_to_event_strings():
235-
_event_to_string(())
235+
_event_to_string((), avoid_realization=True)
236+
_event_to_string((), avoid_realization=False)

hypothesis-python/tests/crosshair/test_crosshair.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,3 +232,11 @@ def test(n):
232232
test()
233233

234234
assert saw_myevent
235+
236+
237+
# see https://github.com/pschanely/hypothesis-crosshair/issues/41
238+
@given(st.integers())
239+
@settings(backend="crosshair")
240+
def test_event_with_realization(value):
241+
event(value)
242+
float(value)

0 commit comments

Comments
 (0)