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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better doc formatting in extra.numpy.arrays() #3360

Merged
merged 9 commits into from Jun 1, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS.rst
Expand Up @@ -50,6 +50,7 @@ their individual contributions.
* `Eduardo Enriquez <https://www.github.com/eduzen>`_ (eduardo.a.enriquez@gmail.com)
* `El Awbery <https://www.github.com/ElAwbery>`_
* `Emmanuel Leblond <https://www.github.com/touilleMan>`_
* `Felix Divo <https://www.github.com/felixdivo>`_
* `Felix Gr眉newald <https://www.github.com/fgruen>`_
* `Felix Sheldon <https://www.github.com/darkpaw>`_
* `Florian Bruhin <https://www.github.com/The-Compiler>`_
Expand Down
4 changes: 4 additions & 0 deletions hypothesis-python/RELEASE.rst
@@ -0,0 +1,4 @@
RELEASE_TYPE: patch

This release contains some small improvements to our documentation.
Thanks to Felix Divo for his contribution!
10 changes: 0 additions & 10 deletions hypothesis-python/docs/changes.rst
Expand Up @@ -27,16 +27,6 @@ Hypothesis 6.x
This patch by Adrian Garcia Badaracco adds type annotations
to some private internals (:issue:`3074`).

This patch by Phillip Schanely makes changes to the
:func:`~hypothesis.strategies.floats` strategy when ``min_value`` or ``max_value`` is
present.
Hypothesis will now be capable of generating every representable value in the bounds.
You may notice that hypothesis is more likely to test values near boundaries, and values
that are very close to zero.

These changes also support future integrations with symbolic execution tools and fuzzers
(:issue:`3086`).

.. _v6.46.8:

-------------------
Expand Down
25 changes: 10 additions & 15 deletions hypothesis-python/src/hypothesis/extra/numpy.py
Expand Up @@ -370,7 +370,7 @@ def arrays(
strategy that generates such values.
* ``elements`` is a strategy for generating values to put in the array.
If it is None a suitable value will be inferred based on the dtype,
which may give any legal value (including eg ``NaN`` for floats).
which may give any legal value (including eg NaN for floats).
If a mapping, it will be passed as ``**kwargs`` to ``from_dtype()``
* ``fill`` is a strategy that may be used to generate a single background
value for the array. If None, a suitable default will be inferred
Expand All @@ -382,41 +382,36 @@ def arrays(
distinct from one another. Note that in this case multiple NaN values
may still be allowed. If fill is also set, the only valid values for
it to return are NaN values (anything for which :obj:`numpy:numpy.isnan`
returns True. So e.g. for complex numbers (nan+1j) is also a valid fill).
Note that if unique is set to True the generated values must be hashable.
returns True. So e.g. for complex numbers ``nan+1j`` is also a valid fill).
Note that if ``unique`` is set to ``True`` the generated values must be
hashable.

Arrays of specified ``dtype`` and ``shape`` are generated for example
like this:

.. code-block:: pycon

>>> import numpy as np
>>> from hypothesis import strategies as st
>>> arrays(np.int8, (2, 3)).example()
array([[-8, 6, 3],
[-6, 4, 6]], dtype=int8)

- See :doc:`What you can generate and how <data>`.

.. code-block:: pycon

>>> import numpy as np
>>> from hypothesis.strategies import floats
>>> arrays(np.float, 3, elements=floats(0, 1)).example()
>>> arrays(np.float, 3, elements=st.floats(0, 1)).example()
array([ 0.88974794, 0.77387938, 0.1977879 ])

Array values are generated in two parts:

1. Some subset of the coordinates of the array are populated with a value
drawn from the elements strategy (or its inferred form).
2. If any coordinates were not assigned in the previous step, a single
value is drawn from the fill strategy and is assigned to all remaining
value is drawn from the ``fill`` strategy and is assigned to all remaining
places.

You can set fill to :func:`~hypothesis.strategies.nothing` if you want to
You can set :func:`fill=nothing() <hypothesis.strategies.nothing>` to
disable this behaviour and draw a value for every element.

If fill is set to None then it will attempt to infer the correct behaviour
automatically: If unique is True, no filling will occur by default.
If ``fill=None``, then it will attempt to infer the correct behaviour
automatically. If ``unique`` is ``True``, no filling will occur by default.
Otherwise, if it looks safe to reuse the values of elements across
multiple coordinates (this will be the case for any inferred strategy, and
for most of the builtins, but is not the case for mutable values or
Expand Down
11 changes: 10 additions & 1 deletion hypothesis-python/src/hypothesis/strategies/_internal/numbers.py
Expand Up @@ -206,7 +206,16 @@ def __init__(
):
super().__init__()
assert isinstance(allow_nan, bool)
assert smallest_nonzero_magnitude > 0.0
assert smallest_nonzero_magnitude >= 0.0, "programmer error if this is negative"
if smallest_nonzero_magnitude == 0.0: # pragma: no cover
raise FloatingPointError(
"Got allow_subnormal=True, but we can't represent subnormal floats "
"right now, in violation of the IEEE-754 floating-point "
"specification. This is usually because something was compiled with "
"-ffast-math or a similar option, which sets global processor state. "
"See https://simonbyrne.github.io/notes/fastmath/ for a more detailed "
"writeup - and good luck!"
)
self.min_value = min_value
self.max_value = max_value
self.allow_nan = allow_nan
Expand Down
7 changes: 1 addition & 6 deletions hypothesis-python/tests/array_api/test_from_dtype.py
Expand Up @@ -95,12 +95,7 @@ def test_can_minimize_floats(xp, xps):
{},
{"min_value": -1},
{"max_value": 1},
pytest.param(
{"min_value": -1, "max_value": 1},
marks=pytest.mark.skip(
reason="FixedBoundFloatStrategy(0, 1) rarely generates subnormals"
),
),
{"min_value": -1, "max_value": 1},
],
)
def test_subnormal_generation(xp, xps, kwargs):
Expand Down
4 changes: 3 additions & 1 deletion hypothesis-python/tests/array_api/test_indices.py
Expand Up @@ -39,7 +39,9 @@ def test_generate_optional_indices(xp, xps, condition):

def test_cannot_generate_newaxis_when_disabled(xp, xps):
"""Strategy does not generate newaxis when disabled (i.e. the default)."""
assert_all_examples(xps.indices((3, 3, 3)), lambda idx: None not in idx)
assert_all_examples(
xps.indices((3, 3, 3)), lambda idx: idx == ... or None not in idx
)


def test_generate_indices_for_0d_shape(xp, xps):
Expand Down
9 changes: 1 addition & 8 deletions hypothesis-python/tests/cover/test_subnormal_floats.py
Expand Up @@ -60,14 +60,7 @@ def test_subnormal_validation(kwargs):
kw(allow_subnormal=True, max_value=1),
kw(allow_subnormal=True, max_value=next_up(-float_info.min)),
# min/max values
kw(
allow_subnormal=True,
min_value=-1,
max_value=1,
marks=pytest.mark.skip(
reason="FixedBoundFloatStrategy(0, 1) rarely generates subnormals"
),
),
kw(allow_subnormal=True, min_value=-1, max_value=1),
kw(
allow_subnormal=True,
min_value=next_down(float_info.min),
Expand Down
2 changes: 1 addition & 1 deletion hypothesis-python/tests/numpy/test_fill_values.py
Expand Up @@ -47,7 +47,7 @@ def test_minimizes_to_fill():
@given(
arrays(
dtype=float,
elements=st.floats().filter(bool),
elements=st.floats(allow_nan=False).filter(bool),
shape=(3, 3, 3),
fill=st.just(1.0),
)
Expand Down
3 changes: 2 additions & 1 deletion hypothesis-python/tests/pytest/test_capture.py
Expand Up @@ -48,7 +48,7 @@ def test_emits_unicode():
@settings(verbosity=Verbosity.verbose)
@given(text())
def test_should_emit_unicode(t):
assert all(ord(c) <= 1000 for c in t)
assert all(ord(c) <= 1000 for c in t), ascii(t)
with pytest.raises(AssertionError):
test_should_emit_unicode()
"""
Expand All @@ -57,6 +57,7 @@ def test_should_emit_unicode(t):
@pytest.mark.xfail(
WINDOWS,
reason="Encoding issues in running the subprocess, possibly pytest's fault",
strict=False, # It's possible, if rare, for this to pass on Windows too.
)
def test_output_emitting_unicode(testdir, monkeypatch):
monkeypatch.setenv("LC_ALL", "C")
Expand Down
6 changes: 3 additions & 3 deletions tooling/src/hypothesistooling/projects/hypothesispython.py
Expand Up @@ -77,9 +77,9 @@ def build_docs(builder="html"):
)


CHANGELOG_ANCHOR = re.compile(r"^\.\. _v\d+\.\d+\.\d+:$")
CHANGELOG_BORDER = re.compile(r"^-+$")
CHANGELOG_HEADER = re.compile(r"^\d+\.\d+\.\d+ - \d\d\d\d-\d\d-\d\d$")
CHANGELOG_ANCHOR = re.compile(r"^\.\. _v\d+\.\d+\.\d+:$", flags=re.MULTILINE)
CHANGELOG_BORDER = re.compile(r"^-+$", flags=re.MULTILINE)
CHANGELOG_HEADER = re.compile(r"^\d+\.\d+\.\d+ - \d\d\d\d-\d\d-\d\d$", flags=re.M)


def update_changelog_and_version():
Expand Down
12 changes: 12 additions & 0 deletions whole-repo-tests/test_release_files.py
Expand Up @@ -12,6 +12,7 @@

import hypothesistooling as tools
from hypothesistooling import releasemanagement as rm
from hypothesistooling.projects import hypothesispython as hp


@pytest.mark.parametrize("project", tools.all_projects())
Expand All @@ -22,3 +23,14 @@ def test_release_file_exists_and_is_valid(project):
"one to describe your changes."
)
rm.parse_release_file(project.RELEASE_FILE)


@pytest.mark.skipif(not hp.has_release(), reason="Checking that release")
def test_release_file_has_no_merge_conflicts():
_, message = rm.parse_release_file(hp.RELEASE_FILE)
assert "<<<" not in message, "Merge conflict in RELEASE.rst"
_, *recent_changes, _ = hp.CHANGELOG_ANCHOR.split(hp.changelog(), maxsplit=12)
for entry in recent_changes:
_, version, old_msg = (x.strip() for x in hp.CHANGELOG_BORDER.split(entry))
assert message not in old_msg, f"Release notes already published for {version}"
assert old_msg not in message, f"Copied {version} release notes - merge error?"