Repository: HypothesisWorks/hypothesis (Python)

Issue:
Deprecate floating-point values for size arguments
https://github.com/HypothesisWorks/hypothesis/blob/859069c52ccf041234971f30aedaf058d91e7bb7/hypothesis-python/src/hypothesis/internal/validation.py#L102-L111

Sizes - the number of elements in a collection, bounded by `min_size` and `max_size` arguments, should always be integers.  However, we currently also accept floats for these arguments!  We should replace the `check_type(integer_types + (float,), value)` with

```python
if isinstance(value, float):
    note_deprecation(...)
else:
    check_type(integer_types, value) 
```

And then write a test in `hypothesis-python/tests/cover/test_validation.py` that uses `@checks_deprecated_behaviour`, passes `max_size=5.0` to `lists()`, and checks that the resulting lists are at most five elements long.

Finally, we should update the type hints for `average_size` arguments to `# type: None` as `None` is the only non-deprecated value.


Discussion:
Hey Zac!
I'm Mridul, a beginner in the field of open source development. I think I can resolve this issue. Can you assign this issue to me?
Sure! It's all yours for the next week - just @-mention me if you have any more questions, and welcome to Hypothesis :sparkles:
> max_size=5.0 to lists(), and checks that the resulting lists are at most five elements long.

What should happen if someone passes `5.2` for example? I've quickly tested, and it seems to do some sort of `math.ceil`.

That seems to be handled on https://github.com/HypothesisWorks/hypothesis/pull/1634 though, so should I just test "whole" float numbers for this issue?



Patch:
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index f4e6efdc24..610265b76c 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -230,6 +230,7 @@ their individual contributions.
 * `Marius Gedminas <https://www.github.com/mgedmin>`_ (marius@gedmin.as)
 * `Markus Unterwaditzer <http://github.com/untitaker/>`_ (markus@unterwaditzer.net)
 * `Matt Bachmann <https://www.github.com/bachmann1234>`_ (bachmann.matt@gmail.com)
+* `Mathieu Paturel <https://github.com/math2001>`_ (mathieu.paturel@gmail.com)
 * `Max Nordlund <https://www.github.com/maxnordlund>`_ (max.nordlund@gmail.com)
 * `Maxim Kulkin <https://www.github.com/maximkulkin>`_ (maxim.kulkin@gmail.com)
 * `mulkieran <https://www.github.com/mulkieran>`_
diff --git a/hypothesis-python/RELEASE.rst b/hypothesis-python/RELEASE.rst
new file mode 100644
index 0000000000..690e195c33
--- /dev/null
+++ b/hypothesis-python/RELEASE.rst
@@ -0,0 +1,8 @@
+RELEASE_TYPE: minor
+
+This release deprecates using floats for ``min_size`` and ``max_size``.
+
+The type hint for ``average_size`` arguments has been changed from
+``Optional[int]`` to None, because non-None values are always ignored and
+deprecated.
+
diff --git a/hypothesis-python/docs/examples.rst b/hypothesis-python/docs/examples.rst
index e2f1b8cbf9..486b1188e7 100644
--- a/hypothesis-python/docs/examples.rst
+++ b/hypothesis-python/docs/examples.rst
@@ -100,7 +100,7 @@ First we need to define a strategy for Node:
   NodeStrategy = s.builds(
     Node,
     s.integers(),
-    s.lists(s.booleans(), average_size=5, max_size=10))
+    s.lists(s.booleans(), max_size=10))
 
 We want to generate *short* lists of values so that there's a decent chance of
 one being a prefix of the other (this is also why the choice of bool as the
diff --git a/hypothesis-python/src/hypothesis/internal/validation.py b/hypothesis-python/src/hypothesis/internal/validation.py
index abe2783bc9..f82c8e5510 100644
--- a/hypothesis-python/src/hypothesis/internal/validation.py
+++ b/hypothesis-python/src/hypothesis/internal/validation.py
@@ -113,11 +113,18 @@ def check_valid_size(value, name):
                 'min_size=None is deprecated; use min_size=0 instead.'
             )
         return
-    check_type(integer_types + (float,), value)
+    if isinstance(value, float):
+        if math.isnan(value):
+            raise InvalidArgument(u'Invalid size %s=%r' % (name, value))
+        from hypothesis._settings import note_deprecation
+        note_deprecation(
+            'Float size are deprecated: '
+            '%s should be an integer, got %r' % (name, value)
+        )
+    else:
+        check_type(integer_types, value)
     if value < 0:
         raise InvalidArgument(u'Invalid size %s=%r < 0' % (name, value))
-    if isinstance(value, float) and math.isnan(value):
-        raise InvalidArgument(u'Invalid size %s=%r' % (name, value))
 
 
 @check_function
diff --git a/hypothesis-python/src/hypothesis/strategies.py b/hypothesis-python/src/hypothesis/strategies.py
index 4fe0d22bbb..7be0a1de7f 100644
--- a/hypothesis-python/src/hypothesis/strategies.py
+++ b/hypothesis-python/src/hypothesis/strategies.py
@@ -602,7 +602,7 @@ def sampled_from(elements):
 def lists(
     elements=None,  # type: SearchStrategy[Ex]
     min_size=0,  # type: int
-    average_size=None,  # type: int
+    average_size=None,  # type: None
     max_size=None,  # type: int
     unique_by=None,  # type: Callable[..., Any]
     unique=False,  # type: bool
@@ -672,7 +672,7 @@ def unique_by(x):
 def sets(
     elements=None,  # type: SearchStrategy[Ex]
     min_size=0,   # type: int
-    average_size=None,  # type: int
+    average_size=None,  # type: None
     max_size=None,  # type: int
 ):
     # type: (...) -> SearchStrategy[Set[Ex]]
@@ -702,7 +702,7 @@ def sets(
 def frozensets(
     elements=None,  # type: SearchStrategy[Ex]
     min_size=0,   # type: int
-    average_size=None,  # type: int
+    average_size=None,  # type: None
     max_size=None,  # type: int
 ):
     # type: (...) -> SearchStrategy[FrozenSet[Ex]]
@@ -789,7 +789,7 @@ def dictionaries(
     values,  # type: SearchStrategy[T]
     dict_class=dict,  # type: type
     min_size=0,  # type: int
-    average_size=None,  # type: int
+    average_size=None,  # type: None
     max_size=None,  # type: int
 ):
     # type: (...) -> SearchStrategy[Dict[Ex, T]]
@@ -937,7 +937,7 @@ def characters(
 def text(
     alphabet=None,  # type: Union[Sequence[Text], SearchStrategy[Text]]
     min_size=0,   # type: int
-    average_size=None,   # type: int
+    average_size=None,   # type: None
     max_size=None  # type: int
 ):
     # type: (...) -> SearchStrategy[Text]


Test patch:
diff --git a/hypothesis-python/tests/cover/test_validation.py b/hypothesis-python/tests/cover/test_validation.py
index b001663194..9bd7fe3d98 100644
--- a/hypothesis-python/tests/cover/test_validation.py
+++ b/hypothesis-python/tests/cover/test_validation.py
@@ -31,6 +31,18 @@ def test_min_size_none_behavior():
     lists(integers(), min_size=None).example()
 
 
+@checks_deprecated_behaviour
+@given(lists(integers(), min_size=5.0))
+def test_min_size_float_behaviour(arr):
+    assert len(arr) >= 5
+
+
+@checks_deprecated_behaviour
+@given(lists(integers(), max_size=5.0))
+def test_max_size_float_behaviour(arr):
+    assert len(arr) <= 5
+
+
 def test_errors_when_given_varargs():
     @given(integers())
     def has_varargs(*args):