Skip to content

Commit 9390b0d

Browse files
committed
report all generated arguments in observability
1 parent 01d5d3e commit 9390b0d

File tree

4 files changed

+49
-11
lines changed

4 files changed

+49
-11
lines changed

hypothesis-python/RELEASE.rst

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
RELEASE_TYPE: patch
2+
3+
This patch fixes a bug where only interactively-generated values (via ``data.draw``) would be reported in the ``arguments`` field of our :doc:`observability output <observability>`. Now, all values are reported.

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

+7-1
Original file line numberDiff line numberDiff line change
@@ -2485,6 +2485,9 @@ def draw(
24852485
label: Optional[int] = None,
24862486
observe_as: Optional[str] = None,
24872487
) -> "Ex":
2488+
from hypothesis.internal.observability import TESTCASE_CALLBACKS
2489+
from hypothesis.strategies._internal.utils import to_jsonable
2490+
24882491
if self.is_find and not strategy.supports_find:
24892492
raise InvalidArgument(
24902493
f"Cannot use strategy {strategy!r} within a call to find "
@@ -2521,7 +2524,7 @@ def draw(
25212524
try:
25222525
strategy.validate()
25232526
try:
2524-
return strategy.do_draw(self)
2527+
v = strategy.do_draw(self)
25252528
finally:
25262529
# Subtract the time spent in GC to avoid overcounting, as it is
25272530
# accounted for at the overall example level.
@@ -2530,6 +2533,9 @@ def draw(
25302533
except Exception as err:
25312534
add_note(err, f"while generating {key[9:]!r} from {strategy!r}")
25322535
raise
2536+
if TESTCASE_CALLBACKS:
2537+
self._observability_args[key] = to_jsonable(v)
2538+
return v
25332539
finally:
25342540
self.stop_example()
25352541

hypothesis-python/src/hypothesis/strategies/_internal/core.py

+3-10
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@
8585
)
8686
from hypothesis.internal.entropy import get_seeder_and_restorer
8787
from hypothesis.internal.floats import float_of
88-
from hypothesis.internal.observability import TESTCASE_CALLBACKS
8988
from hypothesis.internal.reflection import (
9089
define_function_signature,
9190
get_pretty_function_description,
@@ -139,11 +138,7 @@
139138
TextStrategy,
140139
_check_is_single_character,
141140
)
142-
from hypothesis.strategies._internal.utils import (
143-
cacheable,
144-
defines_strategy,
145-
to_jsonable,
146-
)
141+
from hypothesis.strategies._internal.utils import cacheable, defines_strategy
147142
from hypothesis.utils.conventions import not_set
148143
from hypothesis.vendor.pretty import RepresentationPrinter
149144

@@ -2119,15 +2114,13 @@ def draw(self, strategy: SearchStrategy[Ex], label: Any = None) -> Ex:
21192114
check_strategy(strategy, "strategy")
21202115
self.count += 1
21212116
printer = RepresentationPrinter(context=current_build_context())
2122-
desc = f"Draw {self.count}{'' if label is None else f' ({label})'}: "
2117+
desc = f"Draw {self.count}{'' if label is None else f' ({label})'}"
21232118
with deprecate_random_in_strategy("{}from {!r}", desc, strategy):
21242119
result = self.conjecture_data.draw(strategy, observe_as=f"generate:{desc}")
2125-
if TESTCASE_CALLBACKS:
2126-
self.conjecture_data._observability_args[desc] = to_jsonable(result)
21272120

21282121
# optimization to avoid needless printer.pretty
21292122
if should_note():
2130-
printer.text(desc)
2123+
printer.text(f"{desc}: ")
21312124
printer.pretty(result)
21322125
note(printer.getvalue())
21332126
return result

hypothesis-python/tests/cover/test_observability.py

+36
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,42 @@ def test_observability():
6969
)
7070

7171

72+
def test_capture_unnamed_arguments():
73+
@given(st.integers(), st.floats(), st.data())
74+
def f(v1, v2, data):
75+
data.draw(st.booleans())
76+
77+
with capture_observations() as observations:
78+
f()
79+
80+
test_cases = [tc for tc in observations if tc["type"] == "test_case"]
81+
for test_case in test_cases:
82+
assert list(test_case["arguments"].keys()) == [
83+
"generate:v1",
84+
"generate:v2",
85+
"generate:data",
86+
"generate:Draw 1",
87+
], test_case
88+
89+
90+
def test_capture_named_arguments():
91+
@given(named1=st.integers(), named2=st.floats(), data=st.data())
92+
def f(named1, named2, data):
93+
data.draw(st.booleans())
94+
95+
with capture_observations() as observations:
96+
f()
97+
98+
test_cases = [tc for tc in observations if tc["type"] == "test_case"]
99+
for test_case in test_cases:
100+
assert list(test_case["arguments"].keys()) == [
101+
"generate:named1",
102+
"generate:named2",
103+
"generate:data",
104+
"generate:Draw 1",
105+
], test_case
106+
107+
72108
def test_assume_has_status_reason():
73109
@given(st.booleans())
74110
def f(b):

0 commit comments

Comments
 (0)