Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions deps/check.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
#
# pip-compile --annotation-style=line --output-file=deps/check.txt deps/check.in
#
anyio==4.10.0 # via starlette
anyio==4.11.0 # via starlette
attrs==25.3.0 # via hypothesis, outcome, trio
black==25.1.0 # via shed
black==25.9.0 # via shed
click==8.1.8 # via black
com2ann==0.3.0 # via shed
exceptiongroup==1.3.0 # via anyio, hypercorn, hypothesis, pytest, taskgroup, trio
Expand All @@ -16,12 +16,12 @@ h2==4.3.0 # via hypercorn
hpack==4.1.0 # via h2
hypercorn==0.17.3 # via -r deps/check.in
hyperframe==6.1.0 # via h2
hypothesis==6.138.14 # via -r deps/check.in
hypothesis==6.140.2 # via -r deps/check.in
idna==3.10 # via anyio, trio
iniconfig==2.1.0 # via pytest
libcst==1.8.2 # via shed
libcst==1.8.5 # via shed
mccabe==0.7.0 # via flake8
mypy==1.17.1 # via -r deps/check.in
mypy==1.18.2 # via -r deps/check.in
mypy-extensions==1.1.0 # via black, mypy
outcome==1.3.0.post0 # via trio
packaging==25.0 # via black, pytest
Expand All @@ -30,24 +30,25 @@ pep8-naming==0.15.1 # via -r deps/check.in
platformdirs==4.4.0 # via black
pluggy==1.6.0 # via pytest
priority==2.0.0 # via hypercorn
psutil==7.0.0 # via -r deps/check.in
psutil==7.1.0 # via -r deps/check.in
pycodestyle==2.14.0 # via flake8
pyflakes==3.4.0 # via flake8
pygments==2.19.2 # via pytest
pytest==8.4.1 # via -r deps/check.in
pytest==8.4.2 # via -r deps/check.in
pytokens==0.1.10 # via black
pyupgrade==3.20.0 # via shed
pyyaml==6.0.2 # via libcst
ruff==0.12.11 # via -r deps/check.in, shed
pyyaml==6.0.3 # via libcst
ruff==0.13.2 # via -r deps/check.in, shed
shed==2025.6.1 # via -r deps/check.in
sniffio==1.3.1 # via anyio, trio
sortedcontainers==2.4.0 # via hypothesis, sortedcontainers-stubs, trio
sortedcontainers-stubs==2.4.3 # via -r deps/check.in
starlette==0.47.3 # via -r deps/check.in
starlette==0.48.0 # via -r deps/check.in
taskgroup==0.2.2 # via hypercorn
tokenize-rt==6.2.0 # via pyupgrade
tomli==2.2.1 # via black, hypercorn, mypy, pytest
trio==0.30.0 # via -r deps/check.in
types-requests==2.32.4.20250809 # via -r deps/check.in
trio==0.31.0 # via -r deps/check.in
types-requests==2.32.4.20250913 # via -r deps/check.in
typing-extensions==4.15.0 # via anyio, black, exceptiongroup, hypercorn, libcst, mypy, sortedcontainers-stubs, starlette, taskgroup
urllib3==2.5.0 # via types-requests
wsproto==1.2.0 # via hypercorn
27 changes: 14 additions & 13 deletions deps/docs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,33 @@
#
accessible-pygments==0.0.5 # via furo
alabaster==0.7.16 # via sphinx
anyio==4.10.0 # via starlette
anyio==4.11.0 # via starlette
attrs==25.3.0 # via hypothesis, outcome, trio
babel==2.17.0 # via sphinx
beautifulsoup4==4.13.5 # via furo
black==25.1.0 # via hypofuzz (pyproject.toml), hypothesis
beautifulsoup4==4.14.0 # via furo
black==25.9.0 # via hypofuzz (pyproject.toml), hypothesis
certifi==2025.8.3 # via requests
charset-normalizer==3.4.3 # via requests
click==8.1.8 # via black, hypothesis
coverage==7.10.6 # via hypofuzz (pyproject.toml)
coverage==7.10.7 # via hypofuzz (pyproject.toml)
docutils==0.21.2 # via myst-parser, pybtex-docutils, sphinx, sphinxcontrib-bibtex
exceptiongroup==1.3.0 # via anyio, hypercorn, hypothesis, pytest, taskgroup, trio
furo==2025.7.19 # via -r deps/docs.in
furo==2025.9.25 # via -r deps/docs.in
h11==0.16.0 # via hypercorn, wsproto
h2==4.3.0 # via hypercorn
hpack==4.1.0 # via h2
hypercorn==0.17.3 # via hypofuzz (pyproject.toml)
hyperframe==6.1.0 # via h2
hypothesis[cli,watchdog]==6.138.14 # via hypofuzz (pyproject.toml)
hypothesis[cli,watchdog]==6.140.2 # via hypofuzz (pyproject.toml)
idna==3.10 # via anyio, requests, trio
imagesize==1.4.1 # via sphinx
importlib-metadata==8.7.0 # via pybtex, sphinx, sphinxcontrib-bibtex
iniconfig==2.1.0 # via pytest
jinja2==3.1.6 # via myst-parser, sphinx
latexcodec==3.0.1 # via pybtex
libcst==1.8.2 # via hypofuzz (pyproject.toml)
libcst==1.8.5 # via hypofuzz (pyproject.toml)
markdown-it-py==3.0.0 # via mdit-py-plugins, myst-parser, rich
markupsafe==3.0.2 # via jinja2
markupsafe==3.0.3 # via jinja2
mdit-py-plugins==0.4.2 # via myst-parser
mdurl==0.1.2 # via markdown-it-py
mypy-extensions==1.1.0 # via black
Expand All @@ -43,12 +43,13 @@ pathspec==0.12.1 # via black
platformdirs==4.4.0 # via black
pluggy==1.6.0 # via pytest
priority==2.0.0 # via hypercorn
psutil==7.0.0 # via hypofuzz (pyproject.toml)
psutil==7.1.0 # via hypofuzz (pyproject.toml)
pybtex==0.25.1 # via pybtex-docutils, sphinxcontrib-bibtex
pybtex-docutils==1.0.3 # via sphinxcontrib-bibtex
pygments==2.19.2 # via accessible-pygments, furo, pytest, rich, sphinx
pytest==8.4.1 # via hypofuzz (pyproject.toml)
pyyaml==6.0.2 # via libcst, myst-parser, pybtex
pytest==8.4.2 # via hypofuzz (pyproject.toml)
pytokens==0.1.10 # via black
pyyaml==6.0.3 # via libcst, myst-parser, pybtex
requests==2.32.5 # via sphinx
rich==14.1.0 # via hypothesis
sniffio==1.3.1 # via anyio, trio
Expand All @@ -64,10 +65,10 @@ sphinxcontrib-htmlhelp==2.1.0 # via sphinx
sphinxcontrib-jsmath==1.0.1 # via sphinx
sphinxcontrib-qthelp==2.0.0 # via sphinx
sphinxcontrib-serializinghtml==2.0.0 # via sphinx
starlette==0.47.3 # via hypofuzz (pyproject.toml)
starlette==0.48.0 # via hypofuzz (pyproject.toml)
taskgroup==0.2.2 # via hypercorn
tomli==2.2.1 # via black, hypercorn, pytest, sphinx
trio==0.30.0 # via hypofuzz (pyproject.toml)
trio==0.31.0 # via hypofuzz (pyproject.toml)
typing-extensions==4.15.0 # via anyio, beautifulsoup4, black, exceptiongroup, hypercorn, libcst, starlette, taskgroup
urllib3==2.5.0 # via requests
watchdog==6.0.0 # via hypothesis
Expand Down
23 changes: 12 additions & 11 deletions deps/test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,24 @@
#
# pip-compile --annotation-style=line --output-file=deps/test.txt deps/test.in pyproject.toml
#
anyio==4.10.0 # via starlette
anyio==4.11.0 # via starlette
attrs==25.3.0 # via hypothesis, outcome, trio
black==25.1.0 # via hypofuzz (pyproject.toml), hypothesis
black==25.9.0 # via hypofuzz (pyproject.toml), hypothesis
certifi==2025.8.3 # via requests
charset-normalizer==3.4.3 # via requests
click==8.1.8 # via black, hypothesis
coverage[toml]==7.10.6 # via hypofuzz (pyproject.toml), pytest-cov
coverage[toml]==7.10.7 # via hypofuzz (pyproject.toml), pytest-cov
exceptiongroup==1.3.0 # via anyio, hypercorn, hypothesis, pytest, taskgroup, trio
execnet==2.1.1 # via pytest-xdist
h11==0.16.0 # via hypercorn, wsproto
h2==4.3.0 # via hypercorn
hpack==4.1.0 # via h2
hypercorn==0.17.3 # via hypofuzz (pyproject.toml)
hyperframe==6.1.0 # via h2
hypothesis[cli,watchdog]==6.138.14 # via hypofuzz (pyproject.toml)
hypothesis[cli,watchdog]==6.140.2 # via hypofuzz (pyproject.toml)
idna==3.10 # via anyio, requests, trio
iniconfig==2.1.0 # via pytest
libcst==1.8.2 # via hypofuzz (pyproject.toml)
libcst==1.8.5 # via hypofuzz (pyproject.toml)
markdown-it-py==3.0.0 # via rich
mdurl==0.1.2 # via markdown-it-py
mypy-extensions==1.1.0 # via black
Expand All @@ -31,20 +31,21 @@ pathspec==0.12.1 # via black
platformdirs==4.4.0 # via black
pluggy==1.6.0 # via pytest, pytest-cov
priority==2.0.0 # via hypercorn
psutil==7.0.0 # via hypofuzz (pyproject.toml)
psutil==7.1.0 # via hypofuzz (pyproject.toml)
pygments==2.19.2 # via pytest, rich
pytest==8.4.1 # via -r deps/test.in, hypofuzz (pyproject.toml), pytest-cov, pytest-xdist
pytest-cov==6.2.1 # via -r deps/test.in
pytest==8.4.2 # via -r deps/test.in, hypofuzz (pyproject.toml), pytest-cov, pytest-xdist
pytest-cov==7.0.0 # via -r deps/test.in
pytest-xdist==3.8.0 # via -r deps/test.in
pyyaml==6.0.2 # via libcst
pytokens==0.1.10 # via black
pyyaml==6.0.3 # via libcst
requests==2.32.5 # via -r deps/test.in
rich==14.1.0 # via hypothesis
sniffio==1.3.1 # via anyio, trio
sortedcontainers==2.4.0 # via hypothesis, trio
starlette==0.47.3 # via hypofuzz (pyproject.toml)
starlette==0.48.0 # via hypofuzz (pyproject.toml)
taskgroup==0.2.2 # via hypercorn
tomli==2.2.1 # via black, coverage, hypercorn, pytest
trio==0.30.0 # via hypofuzz (pyproject.toml)
trio==0.31.0 # via hypofuzz (pyproject.toml)
typing-extensions==4.15.0 # via anyio, black, exceptiongroup, hypercorn, libcst, starlette, taskgroup
urllib3==2.5.0 # via requests
watchdog==6.0.0 # via hypothesis
Expand Down
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ keywords = ["python", "testing", "fuzzing", "property-based-testing"]
dependencies = [
"black>=23.3.0",
"coverage>=5.2.1",
"hypothesis[cli,watchdog]>=6.138.14",
"hypothesis[cli,watchdog]>=6.140.2",
"libcst>=1.0.0", # for hypothesis.extra._patching
"psutil>=3.0.0",
"pytest>=7.0.0",
Expand Down Expand Up @@ -127,7 +127,6 @@ ignore = [
"E741",
"FBT003",
"PD011",
"PD901",
"PIE790", # See https://github.com/astral-sh/ruff/issues/10538
"PT001",
"PT003",
Expand Down
2 changes: 1 addition & 1 deletion src/hypofuzz/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

from hypofuzz.detection import in_hypofuzz_run

__version__ = "25.09.01"
__version__ = "25.09.02"
__all__: list[str] = ["in_hypofuzz_run"]
6 changes: 6 additions & 0 deletions src/hypofuzz/docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
HypoFuzz uses [calendar-based versioning](https://calver.org/), with a
`YY-MM-patch` format.

(v25-09-02)=
## 25.09.02

* Fix error while running stateful tests
* Support middle click to open links in new tab in more places

(v25-09-01)=
## 25.09.01

Expand Down
8 changes: 7 additions & 1 deletion src/hypofuzz/hypofuzz.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,13 @@ def _new_state(
) -> HypofuzzStateForActualGivenExecution:
arguments: list[Any] = []

if self.pytest_item is not None and isinstance(self.pytest_item.parent, Class):
if (
self.pytest_item is not None
and isinstance(self.pytest_item.parent, Class)
# don't get tricked by the .TestCase class in stateful tests;
# that's already a standard @given test
and not hasattr(self.pytest_item.obj, "_hypothesis_state_machine_class")
):
assert self._pytest_item_instance is not None
# if we're a class-based test, we need to provide the `self` instance
# as the first argument.
Expand Down
4 changes: 3 additions & 1 deletion tests/common.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import dataclasses
import inspect
import os
import queue
Expand Down Expand Up @@ -298,6 +299,7 @@ def write_test_code(path: Path, db_dir, code: str) -> None:
import pytest
from hypothesis import given, settings, strategies as st, HealthCheck, target
from hypothesis.database import DirectoryBasedExampleDatabase
from hypothesis.stateful import RuleBasedStateMachine, rule

from hypofuzz import in_hypofuzz_run

Expand Down Expand Up @@ -334,7 +336,7 @@ def interesting_origin(n: Optional[int] = None) -> InterestingOrigin:
int("not an int")
except Exception as e:
origin = InterestingOrigin.from_exception(e)
return origin._replace(lineno=n if n is not None else origin.lineno)
return dataclasses.replace(origin, lineno=n if n is not None else origin.lineno)


def collect(code: str) -> CollectionResult:
Expand Down
10 changes: 10 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import os

# If this envvar is set, Hypothesis loads the CI profile. We can't combine that
# with hypofuzz, since the CI profile sets derandomize=True, which hypofuzz
# skips during collection.
#
# This has to be changed at the os.environ level, instead of doing
# settings.load_profile("default"), because pytest collection and subprocesses
# inherit the current os.environ and would think themselves as in CI.
os.environ.pop("__TOX_ENVIRONMENT_VARIABLE_ORIGINAL_CI", None)
1 change: 1 addition & 0 deletions tests/test_corpus.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ def observations(
os_getpid=st.just(0),
imported_at=st.just(0.0),
data_status=statuses,
phase=st.just(""),
interesting_origin=st.builds(interesting_origin, n=st.integers()),
choice_nodes=st.lists(nodes()).map(tuple),
choice_spans=st.just(None),
Expand Down
8 changes: 8 additions & 0 deletions tests/test_fuzzing.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ class TestClassBased:
def test_a(self, n):
assert isinstance(self, TestClassBased)
assert isinstance(n, int)
""",
"""
class MyStateMachine(RuleBasedStateMachine):
@rule(n=st.integers())
def step(self, n):
assert isinstance(n, int)

TestMyStateMachine = MyStateMachine.TestCase
""",
],
)
Expand Down
4 changes: 0 additions & 4 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,6 @@ xfail_strict = True
addopts =
-Werror
--tb=short
# --cov=hypofuzz
# --cov-branch
# --cov-report=term-missing:skip-covered
# --cov-fail-under=100

[coverage:report]
exclude_lines =
Expand Down
11 changes: 11 additions & 0 deletions visual_tests/test_stateful.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from hypothesis import strategies as st
from hypothesis.stateful import RuleBasedStateMachine, rule


class SimpleStateMachine(RuleBasedStateMachine):
@rule(n=st.integers())
def step(self, n):
assert isinstance(n, int)


TestStatefulSimple = SimpleStateMachine.TestCase