Skip to content

Commit f91f504

Browse files
committed
Merge branch 'master' into 314
2 parents 3e1afcb + 1f6cd9c commit f91f504

File tree

89 files changed

+1547
-452
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+1547
-452
lines changed

.github/workflows/main.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ jobs:
103103
- check-crosshair-custom-nocover/test_[j-r]*
104104
- check-crosshair-custom-nocover/test_[s-z]*
105105
# - check-crosshair-niche
106+
- check-threading
106107
- check-py39-oldestnumpy
107108
- check-numpy-nightly
108109
fail-fast: false
@@ -203,7 +204,8 @@ jobs:
203204
pip install -r requirements/crosshair.txt
204205
pip install hypothesis-python/
205206
- name: Run tests
206-
run: python -m pytest --numprocesses auto ${{ matrix.whichtests == 'nocover' && 'hypothesis-python/tests/nocover' || 'hypothesis-python/tests/ --ignore=hypothesis-python/tests/nocover/ --ignore=hypothesis-python/tests/quality/ --ignore=hypothesis-python/tests/ghostwriter/ --ignore=hypothesis-python/tests/patching/' }}
207+
# remove this ignore when https://github.com/pschanely/hypothesis-crosshair/issues/40 is fixed
208+
run: python -m pytest -W "ignore:hypothesis.internal.observability.TESTCASE_CALLBACKS is deprecated" --numprocesses auto ${{ matrix.whichtests == 'nocover' && 'hypothesis-python/tests/nocover' || 'hypothesis-python/tests/ --ignore=hypothesis-python/tests/nocover/ --ignore=hypothesis-python/tests/quality/ --ignore=hypothesis-python/tests/ghostwriter/ --ignore=hypothesis-python/tests/patching/' }}
207209

208210
test-osx:
209211
runs-on: macos-latest

.github/workflows/website.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Build website & deploy to GitHub Pages
2+
3+
on:
4+
# Runs on pushes targeting the default branch
5+
push:
6+
branches: ["master"]
7+
8+
# Allows you to run this workflow manually from the Actions tab
9+
workflow_dispatch:
10+
11+
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
12+
permissions:
13+
contents: read
14+
pages: write
15+
id-token: write
16+
17+
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
18+
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
19+
concurrency:
20+
group: "pages"
21+
cancel-in-progress: false
22+
23+
jobs:
24+
# Single deploy job since we're just deploying
25+
deploy:
26+
environment:
27+
name: github-pages
28+
url: ${{ steps.deployment.outputs.page_url }}
29+
runs-on: ubuntu-latest
30+
steps:
31+
- name: Checkout
32+
uses: actions/checkout@v4
33+
- name: Build website
34+
run: ./build.sh website
35+
- name: Upload artifact
36+
uses: actions/upload-pages-artifact@v3
37+
with:
38+
path: 'website/output/'
39+
- name: Deploy to GitHub Pages
40+
id: deployment
41+
uses: actions/deploy-pages@v4

hypothesis-python/RELEASE-sample.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ which should:
2727
- :class:`package.class` for link to classes (abbreviated as above).
2828
- :issue:`issue-number` for referencing issues.
2929
- Similarly, :pull:`pr-number` can be used for PRs, but it's usually
30-
preferred to refer to version numbers such as :ref:`version 6.98.9 <v6.98.9>,
30+
preferred to refer to version numbers with :v:`6.98.9`,
3131
as they are meaningful to end users.
3232
- :doc:`link text <chapter#anchor>` for documentation references.
3333
- `link text <https://hypothesis.readthedocs.io/en/latest/chapter.html#anchor>`__

hypothesis-python/docs/changelog.rst

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,48 @@ Hypothesis 6.x
1818

1919
.. include:: ../RELEASE.rst
2020

21+
.. _v6.137.1:
22+
23+
--------------------
24+
6.137.1 - 2025-08-05
25+
--------------------
26+
27+
Fixes a bug with solver-based :ref:`alternative backends <alternative-backends>` (like `crosshair <https://github.com/pschanely/CrossHair>`_) where symbolic values passed to |event| would not be realized to concrete values at the end of the test case.
28+
29+
.. _v6.137.0:
30+
31+
--------------------
32+
6.137.0 - 2025-08-05
33+
--------------------
34+
35+
Add the |add_observability_callback|, |remove_observability_callback|, |with_observability_callback|, and |observability_enabled| methods to the :ref:`observability <observability>` interface. The previous |TESTCASE_CALLBACKS| is deprecated.
36+
37+
This release also adds better threading support to observability callbacks. An observability callback will now only be called for observations generated by the same thread.
38+
39+
.. _v6.136.9:
40+
41+
--------------------
42+
6.136.9 - 2025-08-04
43+
--------------------
44+
45+
Fix a threading race condition in |st.one_of| initialization.
46+
47+
.. _v6.136.8:
48+
49+
--------------------
50+
6.136.8 - 2025-08-04
51+
--------------------
52+
53+
Improve the error messages and documentation for |HealthCheck|. Among others, the messaging is now more clear that health checks are proactive warnings, not correctness errors.
54+
55+
.. _v6.136.7:
56+
57+
--------------------
58+
6.136.7 - 2025-08-01
59+
--------------------
60+
61+
Improve detection of sys.monitoring to avoid errors on GraalPy.
62+
2163
.. _v6.136.6:
2264

2365
--------------------

hypothesis-python/docs/compatibility.rst

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
=============
21
Compatibility
32
=============
43

@@ -7,7 +6,6 @@ possibly need it to be compatible with. Generally you should just try it and
76
expect it to work. If it doesn't, you can be surprised and check this document
87
for the details.
98

10-
-------------------
119
Hypothesis versions
1210
-------------------
1311

@@ -24,7 +22,6 @@ changes in patch releases.
2422

2523
.. _deprecation-policy:
2624

27-
------------
2825
Deprecations
2926
------------
3027

@@ -41,7 +38,6 @@ exactly where an error came from, or turn only our warnings into errors.
4138
.. autoclass:: hypothesis.errors.HypothesisDeprecationWarning
4239

4340

44-
---------------
4541
Python versions
4642
---------------
4743

@@ -55,7 +51,6 @@ patch release of any version of Python it supports. Earlier releases should work
5551
and bugs in them will get fixed if reported, but they're not tested in CI and
5652
no guarantees are made.
5753

58-
-----------------
5954
Operating systems
6055
-----------------
6156

@@ -69,7 +64,6 @@ operating system it probably won't stay fixed due to the inevitable march of tim
6964

7065
.. _framework-compatibility:
7166

72-
------------------
7367
Testing frameworks
7468
------------------
7569

@@ -106,7 +100,6 @@ In terms of what's actually *known* to work:
106100
* :pypi:`coverage` works out of the box with Hypothesis; our own test suite has
107101
100% branch coverage.
108102

109-
-----------------
110103
Optional packages
111104
-----------------
112105

@@ -117,23 +110,33 @@ all versions that are supported upstream.
117110

118111
.. _thread-safety-policy:
119112

120-
--------------------
121113
Thread-Safety Policy
122114
--------------------
123115

124-
As discussed in :issue:`2719`, Hypothesis is not truly thread-safe and that's unlikely to change in the future. This policy therefore describes what you *can* expect if you use Hypothesis with multiple threads.
116+
As of :version:`6.136.9`, Hypothesis is thread-safe. Each of the following is fully supported, and tested regularly in CI:
125117

126-
**Running tests in multiple processes**, e.g. with ``pytest -n auto``, is fully supported and we test this regularly in CI - thanks to process isolation, we only need to ensure that :class:`~hypothesis.database.DirectoryBasedExampleDatabase` can't tread on its own toes too badly. If you find a bug here we will fix it ASAP.
118+
* Running tests in multiple processes
119+
* Running separate tests in multiple threads
120+
* Running the same test in multiple threads
127121

128-
**Running separate tests in multiple threads** is not something we design or test for, and is not formally supported. That said, anecdotally it does mostly work and we would like it to keep working - we accept reasonable patches and low-priority bug reports. The main risks here are global state, shared caches, and cached strategies.
122+
If you find a bug here, please report it. The main risks internally are global state, shared caches, and cached strategies.
129123

130-
**Running the same test in multiple threads**, or using multiple threads within the same test, makes it pretty easy to trigger internal errors. We usually accept patches for such issues unless readability or single-thread performance suffer.
124+
Thread usage inside tests
125+
~~~~~~~~~~~~~~~~~~~~~~~~~
131126

132-
Hypothesis assumes that tests are single-threaded, or do a sufficiently-good job of pretending to be single-threaded. Tests that use helper threads internally should be OK, but the user must be careful to ensure that test outcomes are still deterministic. In particular it counts as nondeterministic if helper-thread timing changes the sequence of dynamic draws using e.g. the |st.data| strategy.
127+
.. TODO_DOCS: link to not-yet-merged flaky failure tutorial page
133128
134-
Interacting with any Hypothesis APIs from helper threads might do weird/bad things, so avoid that too - we rely on thread-local variables in a few places, and haven't explicitly tested/audited how they respond to cross-thread API calls. While |st.data| and equivalents are the most obvious danger, other APIs might also be subtly affected.
129+
Tests that spawn threads internally are supported by Hypothesis.
130+
131+
However, these as with any Hypothesis test, these tests must have deterministic test outcomes and data generation. For example, if timing changes in the threads change the sequence of dynamic draws from |st.composite| or |st.data|, Hypothesis may report the test as flaky. The solution here is to refactor data generation so it does not depend on test timings.
132+
133+
Cross-thread API calls
134+
~~~~~~~~~~~~~~~~~~~~~~
135+
136+
In theory, Hypothesis supports cross-thread API calls, for instance spawning a thread inside of a test and using that to draw from |st.composite| or |st.data|, or to call |event|, |target|, or |assume|.
137+
138+
However, we have not explicitly audited this behavior, and do not regularly test it in our CI. If you find a bug here, please report it. If our investigation determines that we cannot support cross-thread calls for the feature in question, we will update this page accordingly.
135139

136-
----------
137140
Type hints
138141
----------
139142

hypothesis-python/docs/conf.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
import types
1515
from pathlib import Path
1616

17+
from docutils import nodes
18+
from sphinx.util.docutils import SphinxRole
19+
1720
root = Path(__file__).parent.parent
1821
sys.path.append(str(root / "src"))
1922
sys.path.append(str(Path(__file__).parent / "_ext"))
@@ -87,6 +90,22 @@
8790
release = _d["__version__"]
8891

8992

93+
# custom role for version syntaxes.
94+
# :v:`6.131.0` = [v6.131.0](changelog.html#v6.13.0)
95+
# :version:`6.131.0` = [version 6.131.0](changelog.html#v6.13.0)
96+
class VersionRole(SphinxRole):
97+
def __init__(self, prefix):
98+
self.prefix = prefix
99+
100+
def run(self):
101+
node = nodes.reference(
102+
"",
103+
f"{self.prefix}{self.text}",
104+
refuri=f"changelog.html#v{self.text.replace('.', '-')}",
105+
)
106+
return [node], []
107+
108+
90109
def setup(app):
91110
if root.joinpath("RELEASE.rst").is_file():
92111
app.tags.add("has_release_file")
@@ -131,6 +150,8 @@ def process_signature(app, what, name, obj, options, signature, return_annotatio
131150
return signature, return_annotation
132151

133152
app.connect("autodoc-process-signature", process_signature)
153+
app.add_role("v", VersionRole(prefix="v"))
154+
app.add_role("version", VersionRole(prefix="version "))
134155

135156

136157
language = "en"

hypothesis-python/docs/prolog.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,13 @@
104104
.. |settings.load_profile| replace:: :func:`~hypothesis.settings.load_profile`
105105

106106
.. |SearchStrategy| replace:: :class:`~hypothesis.strategies.SearchStrategy`
107+
.. |filter| replace:: :func:`.filter() <hypothesis.strategies.SearchStrategy.filter>`
107108
.. |.filter| replace:: :func:`.filter() <hypothesis.strategies.SearchStrategy.filter>`
108109
.. |.filter()| replace:: :func:`.filter() <hypothesis.strategies.SearchStrategy.filter>`
110+
.. |flatmap| replace:: :func:`.flatmap() <hypothesis.strategies.SearchStrategy.flatmap>`
109111
.. |.flatmap| replace:: :func:`.flatmap() <hypothesis.strategies.SearchStrategy.flatmap>`
110112
.. |.flatmap()| replace:: :func:`.flatmap() <hypothesis.strategies.SearchStrategy.flatmap>`
113+
.. |map| replace:: :func:`.map() <hypothesis.strategies.SearchStrategy.map>`
111114
.. |.map| replace:: :func:`.map() <hypothesis.strategies.SearchStrategy.map>`
112115
.. |.map()| replace:: :func:`.map() <hypothesis.strategies.SearchStrategy.map>`
113116
.. |.example()| replace:: :func:`.example() <hypothesis.strategies.SearchStrategy.example>`
@@ -128,6 +131,11 @@
128131
.. |PrimitiveProvider.span_end| replace:: :func:`~hypothesis.internal.conjecture.providers.PrimitiveProvider.span_end`
129132

130133
.. |AVAILABLE_PROVIDERS| replace:: :data:`~hypothesis.internal.conjecture.providers.AVAILABLE_PROVIDERS`
134+
135+
.. |add_observability_callback| replace:: :data:`~hypothesis.internal.observability.add_observability_callback`
136+
.. |remove_observability_callback| replace:: :data:`~hypothesis.internal.observability.remove_observability_callback`
137+
.. |with_observability_callback| replace:: :data:`~hypothesis.internal.observability.with_observability_callback`
138+
.. |observability_enabled| replace:: :data:`~hypothesis.internal.observability.observability_enabled`
131139
.. |TESTCASE_CALLBACKS| replace:: :data:`~hypothesis.internal.observability.TESTCASE_CALLBACKS`
132140
.. |OBSERVABILITY_CHOICES| replace:: :data:`~hypothesis.internal.observability.OBSERVABILITY_CHOICES`
133141
.. |BUFFER_SIZE| replace:: :data:`~hypothesis.internal.conjecture.engine.BUFFER_SIZE`

hypothesis-python/docs/reference/api.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ Note that the interpretation of both input and output bytestrings is specific to
478478
Interaction with settings
479479
~~~~~~~~~~~~~~~~~~~~~~~~~
480480

481-
``fuzz_one_input`` uses just enough of Hypothesis' internals to drive your test function with a fuzzer-provided bytestring, and most settings therefore have no effect in this mode. We recommend running your tests the usual way before fuzzing to get the benefits of healthchecks, as well as afterwards to replay, shrink, deduplicate, and report whatever errors were discovered.
481+
``fuzz_one_input`` uses just enough of Hypothesis' internals to drive your test function with a fuzzer-provided bytestring, and most settings therefore have no effect in this mode. We recommend running your tests the usual way before fuzzing to get the benefits of health checks, as well as afterwards to replay, shrink, deduplicate, and report whatever errors were discovered.
482482

483483
- The :obj:`~hypothesis.settings.database` setting *is* used by fuzzing mode - adding failures to the database to be replayed when you next run your tests is our preferred reporting mechanism and response to `the 'fuzzer taming' problem <https://blog.regehr.org/archives/925>`__.
484484
- The :obj:`~hypothesis.settings.verbosity` and :obj:`~hypothesis.settings.stateful_step_count` settings work as usual.

hypothesis-python/docs/reference/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ API Reference
33

44
The technical API reference for Hypothesis is split into four pages:
55

6-
* :doc:`API Reference </reference/api>`. Non-strategy Hypothesis objects, classes, and functions.
6+
* :doc:`API Reference </reference/api>`. Non-strategy Hypothesis objects, classes, and functions. |@given| and others live here.
77
* :doc:`Strategies Reference </reference/strategies>`. Hypothesis strategies, including for :doc:`extras </extras>`.
88
* :doc:`Integrations Reference </reference/integrations>`. Features with a defined interface, but no code API.
99
* :doc:`Hypothesis internals </reference/internals>`. Internal APIs for developers building tools, libraries, or research on top of Hypothesis.

hypothesis-python/docs/reference/internals.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ Alternative backends
3030
Observability
3131
-------------
3232

33+
.. autofunction:: hypothesis.internal.observability.add_observability_callback
34+
.. autofunction:: hypothesis.internal.observability.remove_observability_callback
35+
.. autofunction:: hypothesis.internal.observability.with_observability_callback
36+
.. autofunction:: hypothesis.internal.observability.observability_enabled
37+
3338
.. autodata:: hypothesis.internal.observability.TESTCASE_CALLBACKS
3439
.. autodata:: hypothesis.internal.observability.OBSERVABILITY_COLLECT_COVERAGE
3540
.. autodata:: hypothesis.internal.observability.OBSERVABILITY_CHOICES

0 commit comments

Comments
 (0)