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

Add support for crosshair backend #3806

Merged
merged 46 commits into from
Mar 9, 2024
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
2ec0e1d
wip
tybug Feb 16, 2024
e514d73
wip
tybug Feb 23, 2024
93d4636
Merge branch 'master' into provider-plugins-2
tybug Feb 23, 2024
751498d
bad debugging
tybug Feb 23, 2024
0a9881a
update for crosshair
tybug Feb 24, 2024
09894e2
Merge branch 'master' into provider-plugins-2
tybug Feb 24, 2024
87aab30
formatting and remove some debug
tybug Feb 24, 2024
f22c875
update IRTypeName
tybug Feb 24, 2024
f6863f7
fix PrngProvider weights
tybug Feb 24, 2024
074a696
add post_test_case_hook
tybug Feb 24, 2024
8a9f916
format
tybug Feb 24, 2024
71e53a3
abstract to _pop_ir_tree_value
tybug Feb 24, 2024
66d3999
typing
tybug Feb 24, 2024
e49a0eb
better backend database/shrinking
tybug Feb 24, 2024
76a9b57
format
tybug Feb 24, 2024
cfa4133
default result to None
tybug Feb 29, 2024
447bf8b
require post_test_case_hook to be nonnull
tybug Feb 29, 2024
9c1e375
remove unecessary context wrapper
tybug Feb 29, 2024
c5e4d2c
move hacky context manager to the provider interface
tybug Mar 2, 2024
e11822c
Merge branch 'master' into provider-plugins
tybug Mar 4, 2024
ede32b2
update for new ir structure
tybug Mar 4, 2024
490d940
Merge branch 'master' into provider-plugins
tybug Mar 4, 2024
58eaf78
implement fake_forced
tybug Mar 4, 2024
308ca92
add test for backend shrinking ability
tybug Mar 4, 2024
443c3bb
wording
tybug Mar 5, 2024
e636675
extract PrimitiveProvider to interface, add lifetime attr
tybug Mar 5, 2024
142afb9
add track_redundant_inputs attr
tybug Mar 5, 2024
c707955
prefer NotImplementedError to pass
tybug Mar 5, 2024
46ed532
typing
tybug Mar 5, 2024
60915c3
fix backend default
tybug Mar 5, 2024
2ac416a
make test easier to pass
tybug Mar 5, 2024
f409f7b
add tests for backend attrs and shrinking
tybug Mar 5, 2024
7c1b229
reword comment
tybug Mar 5, 2024
d9de115
remove track_redundant_inputs :(
tybug Mar 5, 2024
079b8ea
type ignore setting
tybug Mar 5, 2024
8329f95
reword comment again
tybug Mar 5, 2024
f868f00
update ghostwriter for backend
tybug Mar 5, 2024
eb0a7bc
lint
tybug Mar 5, 2024
6cdf683
did not mean to delete that
tybug Mar 5, 2024
f180bf3
use BUFFER_SIZE
tybug Mar 6, 2024
6678233
remove database=None
tybug Mar 6, 2024
beac7df
remove stale condition, that doesnt play well with new backends
tybug Mar 9, 2024
d94b801
remove prng provider seeding
tybug Mar 9, 2024
ec3ef6c
format
tybug Mar 9, 2024
7e1a86c
Small cleanups
Zac-HD Mar 9, 2024
7322913
correct lifetime recommendation
tybug Mar 9, 2024
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
4 changes: 4 additions & 0 deletions hypothesis-python/RELEASE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
RELEASE_TYPE: minor

This release adds the **experimental and unstable** :obj:`~hypothesis.settings.backend`
setting. See :ref:`alternative-backends` for details.
33 changes: 33 additions & 0 deletions hypothesis-python/docs/strategies.rst
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,36 @@ loading our pytest plugin from your ``conftest.py`` instead::

echo "pytest_plugins = ['hypothesis.extra.pytestplugin']\n" > tests/conftest.py
pytest -p "no:hypothesispytest" ...


.. _alternative-backends:

-----------------------------------
Alternative backends for Hypothesis
-----------------------------------

.. warning::

EXPERIMENTAL AND UNSTABLE.

The importable name of a backend which Hypothesis should use to generate primitive
types. We aim to support heuristic-random, solver-based, and fuzzing-based backends.

See :issue:`3086` for details, e.g. if you're interested in writing your own backend.
(note that there is *no stable interface* for this; you'd be helping us work out
what that should eventually look like, and we're likely to make regular breaking
changes for some time to come)

Using the prototype :pypi:`crosshair-tool` backend `via this schemathesis
Zac-HD marked this conversation as resolved.
Show resolved Hide resolved
<https://github.com/pschanely/hypothesis-crosshair>`__,
a solver-backed test might look something like:

.. code-block:: python

from hypothesis import given, settings, strategies as st


@settings(backend="crosshair", database=None)
Zac-HD marked this conversation as resolved.
Show resolved Hide resolved
@given(st.integers())
def test_needs_solver(x):
assert x != 123456789
2 changes: 2 additions & 0 deletions hypothesis-python/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ def local_file(name):
# We also leave the choice of timezone library to the user, since it
# might be zoneinfo or pytz depending on version and configuration.
"django": ["django>=3.2"],
# TODO: https://github.com/pschanely/hypothesis-crosshair/ extra once released
# "crosshair": ["hypothesis-crosshair-tool >= ???"],
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also set up for an Atheris backend with test_foo.hypothesis.fuzz_with_atheris(*, stop_on_fail: bool) method.

}

extras["all"] = sorted(set(sum(extras.values(), [])))
Expand Down
31 changes: 30 additions & 1 deletion hypothesis-python/src/hypothesis/_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ def __init__(
suppress_health_check: Collection["HealthCheck"] = not_set, # type: ignore
deadline: Union[int, float, datetime.timedelta, None] = not_set, # type: ignore
print_blob: bool = not_set, # type: ignore
backend: str = not_set, # type: ignore
) -> None:
if parent is not None:
check_type(settings, parent, "parent")
Expand Down Expand Up @@ -289,7 +290,13 @@ def __setattr__(self, name, value):
raise AttributeError("settings objects are immutable")

def __repr__(self):
bits = sorted(f"{name}={getattr(self, name)!r}" for name in all_settings)
from hypothesis.internal.conjecture.data import AVAILABLE_PROVIDERS

bits = sorted(
f"{name}={getattr(self, name)!r}"
for name in all_settings
if (name != "backend" or len(AVAILABLE_PROVIDERS) > 1) # experimental
)
return "settings({})".format(", ".join(bits))

def show_changed(self):
Expand Down Expand Up @@ -706,6 +713,28 @@ def is_in_ci() -> bool:
""",
)


def _backend_validator(value):
from hypothesis.internal.conjecture.data import AVAILABLE_PROVIDERS

if value not in AVAILABLE_PROVIDERS:
msg = f"Invalid backend, {value!r}. Valid options: {sorted(AVAILABLE_PROVIDERS)!r}"
Zac-HD marked this conversation as resolved.
Show resolved Hide resolved
raise InvalidArgument(msg)
return value


settings._define_setting(
"backend",
default="hypothesis",
show_default=False,
validator=_backend_validator,
description="""
EXPERIMENTAL AND UNSTABLE - see :ref:`alternative-backends`.
The importable name of a backend which Hypothesis should use to generate primitive
types. We aim to support heuristic-random, solver-based, and fuzzing-based backends.
""",
)

settings.lock_further_definitions()


Expand Down
10 changes: 7 additions & 3 deletions hypothesis-python/src/hypothesis/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -938,9 +938,13 @@ def run(data):
with local_settings(self.settings):
with deterministic_PRNG():
with BuildContext(data, is_final=is_final) as context:
# Run the test function once, via the executor hook.
# In most cases this will delegate straight to `run(data)`.
result = self.test_runner(data, run)
# providers may throw in per_case_context_fn, and we'd like
# `result` to still be set in these cases.
result = None
with data.provider.per_test_case_context_manager():
# Run the test function once, via the executor hook.
# In most cases this will delegate straight to `run(data)`.
result = self.test_runner(data, run)

# If a failure was expected, it should have been raised already, so
# instead raise an appropriate diagnostic error.
Expand Down