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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve pytest error tracebacks and fix weakref error in event() #3392

Merged
merged 2 commits into from Jul 3, 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
4 changes: 4 additions & 0 deletions hypothesis-python/RELEASE.rst
@@ -0,0 +1,4 @@
RELEASE_TYPE: patch

:func:`hypothesis.event` now works for hashable objects which do not
support weakrefs, such as integers and tuples.
9 changes: 7 additions & 2 deletions hypothesis-python/src/_hypothesis_pytestplugin.py
Expand Up @@ -180,6 +180,7 @@ def pytest_configure(config):

@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_call(item):
__tracebackhide__ = True
if not (hasattr(item, "obj") and "hypothesis" in sys.modules):
yield
return
Expand All @@ -192,10 +193,14 @@ def pytest_runtest_call(item):
if not is_hypothesis_test(item.obj):
# If @given was not applied, check whether other hypothesis
# decorators were applied, and raise an error if they were.
# We add this frame of indirection to enable __tracebackhide__.
def raise_hypothesis_usage_error(msg):
raise InvalidArgument(msg)

if getattr(item.obj, "is_hypothesis_strategy_function", False):
from hypothesis.errors import InvalidArgument

raise InvalidArgument(
raise_hypothesis_usage_error(
f"{item.nodeid} is a function that returns a Hypothesis strategy, "
"but pytest has collected it as a test function. This is useless "
"as the function body will never be executed. To define a test "
Expand All @@ -211,7 +216,7 @@ def pytest_runtest_call(item):
if hasattr(item.obj, attribute):
from hypothesis.errors import InvalidArgument

raise InvalidArgument(message % (name,))
raise_hypothesis_usage_error(message % (name,))
yield
else:
from hypothesis import HealthCheck, settings
Expand Down
Expand Up @@ -1067,10 +1067,13 @@ def event_to_string(self, event):
return event
try:
return self.events_to_strings[event]
except KeyError:
except (KeyError, TypeError):
pass
result = str(event)
self.events_to_strings[event] = result
try:
self.events_to_strings[event] = result
except TypeError:
pass
return result


Expand Down
5 changes: 5 additions & 0 deletions hypothesis-python/tests/conjecture/test_engine.py
Expand Up @@ -1587,3 +1587,8 @@ def test(data):
runner.cached_test_function([c])

assert runner.tree.is_exhausted


def test_can_convert_non_weakref_types_to_event_strings():
runner = ConjectureRunner(lambda data: None)
runner.event_to_string(())
5 changes: 5 additions & 0 deletions hypothesis-python/tests/cover/test_statistical_events.py
Expand Up @@ -254,3 +254,8 @@ def test(value):
stats = describe_statistics(call_for_statistics(test))
assert "- Events:" in stats
assert "- Highest target score: " in stats


@given(st.booleans())
def test_event_with_non_weakrefable_keys(b):
event((b,))
4 changes: 3 additions & 1 deletion hypothesis-python/tests/pytest/test_checks.py
Expand Up @@ -33,4 +33,6 @@ def test_repro_without_given_fails():

def test_decorators_without_given_should_fail(testdir):
script = testdir.makepyfile(TEST_DECORATORS_ALONE)
testdir.runpytest(script).assert_outcomes(failed=4)
result = testdir.runpytest(script)
result.assert_outcomes(failed=4)
assert "pytest_runtest_call" not in "\n".join(result.outlines)