Repository: HypothesisWorks/hypothesis

Issue:
target() doesn't work with int input
If you call `target()` with an `int` input, you get an error like `hypothesis.errors.InvalidArgument: Expected float but got observation=1 (type=int)`. It's rather unpythonic for a function that takes float inputs to not also work with ints.


Discussion:
We had originally restricted this to floats-only to keep our options open for later, but I've played around with some plausible other uses now and accepting integers or finite floats would be fine for all of them.  Let's just loosen the check!
I'm looking at this (as part of the PyCon sprints!)

Resolving patch:
diff --git a/hypothesis-python/src/hypothesis/control.py b/hypothesis-python/src/hypothesis/control.py
--- a/hypothesis-python/src/hypothesis/control.py
+++ b/hypothesis-python/src/hypothesis/control.py
@@ -15,7 +15,7 @@
 
 import math
 import traceback
-from typing import Any
+from typing import Any, Union
 
 from hypothesis import Verbosity, settings
 from hypothesis.errors import CleanupFailed, InvalidArgument, UnsatisfiedAssumption
@@ -125,8 +125,8 @@ def event(value: str) -> None:
 
 
 @deprecated_posargs
-def target(observation: float, *, label: str = "") -> None:
-    """Calling this function with a ``float`` observation gives it feedback
+def target(observation: Union[int, float], *, label: str = "") -> None:
+    """Calling this function with an ``int`` or ``float`` observation gives it feedback
     with which to guide our search for inputs that will cause an error, in
     addition to all the usual heuristics.  Observations must always be finite.
 
@@ -165,7 +165,7 @@ def target(observation: float, *, label: str = "") -> None:
     <https://hypothesis.works/articles/threshold-problem/>`__ when the minimal
     example shrinks right down to the threshold of failure (:issue:`2180`).
     """
-    check_type(float, observation, "observation")
+    check_type((int, float), observation, "observation")
     if not math.isfinite(observation):
         raise InvalidArgument("observation=%r must be a finite float." % observation)
     check_type(str, label, "label")


Test patch:
diff --git a/hypothesis-python/tests/cover/test_targeting.py b/hypothesis-python/tests/cover/test_targeting.py
--- a/hypothesis-python/tests/cover/test_targeting.py
+++ b/hypothesis-python/tests/cover/test_targeting.py
@@ -22,13 +22,17 @@
 
 
 @example(0.0, "this covers the branch where context.data is None")
-@given(observation=st.floats(allow_nan=False, allow_infinity=False), label=st.text())
+@given(
+    observation=st.integers() | st.floats(allow_nan=False, allow_infinity=False),
+    label=st.text(),
+)
 def test_allowed_inputs_to_target(observation, label):
     target(observation, label=label)
 
 
 @given(
-    observation=st.floats(min_value=1, allow_nan=False, allow_infinity=False),
+    observation=st.integers(min_value=1)
+    | st.floats(min_value=1, allow_nan=False, allow_infinity=False),
     label=st.sampled_from(["a", "few", "labels"]),
 )
 def test_allowed_inputs_to_target_fewer_labels(observation, label):
@@ -80,7 +84,7 @@ def everything_except(type_):
 @example(float("-inf"), "")
 @example("1", "Non-float observations are invalid")
 @example(0.0, ["a list of strings is not a valid label"])
-@given(observation=everything_except(float), label=everything_except(str))
+@given(observation=everything_except((float, int)), label=everything_except(str))
 def test_disallowed_inputs_to_target(observation, label):
     with pytest.raises(InvalidArgument):
         target(observation, label=label)