Coverage for /usr/local/lib/python3.7/site-packages/hypothesis/extra/pytestplugin.py : 27%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# This file is part of Hypothesis, which may be found at
2# https://github.com/HypothesisWorks/hypothesis/
3#
4# Most of this work is copyright (C) 2013-2020 David R. MacIver
5# (david@drmaciver.com), but it contains contributions by others. See
6# CONTRIBUTING.rst for a full list of people who may hold copyright, and
7# consult the git log if you need to determine who owns an individual
8# contribution.
9#
10# This Source Code Form is subject to the terms of the Mozilla Public License,
11# v. 2.0. If a copy of the MPL was not distributed with this file, You can
12# obtain one at https://mozilla.org/MPL/2.0/.
13#
14# END HEADER
16from distutils.version import LooseVersion
18import pytest
20from hypothesis import Verbosity, core, settings
21from hypothesis.errors import InvalidArgument
22from hypothesis.internal.detection import is_hypothesis_test
23from hypothesis.reporting import default as default_reporter, with_reporter
24from hypothesis.statistics import collector
26LOAD_PROFILE_OPTION = "--hypothesis-profile"
27VERBOSITY_OPTION = "--hypothesis-verbosity"
28PRINT_STATISTICS_OPTION = "--hypothesis-show-statistics"
29SEED_OPTION = "--hypothesis-seed"
32class StoringReporter:
33 def __init__(self, config):
34 self.config = config
35 self.results = []
37 def __call__(self, msg):
38 if self.config.getoption("capture", "fd") == "no":
39 default_reporter(msg)
40 if not isinstance(msg, str):
41 msg = repr(msg)
42 self.results.append(msg)
45if LooseVersion(pytest.__version__) < "4.3": # pragma: no cover
46 import warnings
47 from hypothesis.errors import HypothesisWarning
49 PYTEST_TOO_OLD_MESSAGE = """
50 You are using Pytest version %s. Hypothesis tests work with any test
51 runner, but our Pytest plugin requires Pytest 4.3 or newer.
52 Note that the Pytest developers no longer support this version either!
53 Disabling the Hypothesis pytest plugin...
54 """
55 warnings.warn(PYTEST_TOO_OLD_MESSAGE % (pytest.__version__,), HypothesisWarning)
57else:
59 def pytest_addoption(parser):
60 group = parser.getgroup("hypothesis", "Hypothesis")
61 group.addoption(
62 LOAD_PROFILE_OPTION,
63 action="store",
64 help="Load in a registered hypothesis.settings profile",
65 )
66 group.addoption(
67 VERBOSITY_OPTION,
68 action="store",
69 choices=[opt.name for opt in Verbosity],
70 help="Override profile with verbosity setting specified",
71 )
72 group.addoption(
73 PRINT_STATISTICS_OPTION,
74 action="store_true",
75 help="Configure when statistics are printed",
76 default=False,
77 )
78 group.addoption(
79 SEED_OPTION,
80 action="store",
81 help="Set a seed to use for all Hypothesis tests",
82 )
84 def pytest_report_header(config):
85 profile = config.getoption(LOAD_PROFILE_OPTION)
86 if not profile:
87 profile = settings._current_profile
88 settings_str = settings.get_profile(profile).show_changed()
89 if settings_str != "":
90 settings_str = " -> %s" % (settings_str)
91 if (
92 config.option.verbose >= 1
93 or settings.default.verbosity >= Verbosity.verbose
94 ):
95 return "hypothesis profile %r%s" % (profile, settings_str)
97 def pytest_configure(config):
98 core.running_under_pytest = True
99 profile = config.getoption(LOAD_PROFILE_OPTION)
100 if profile:
101 settings.load_profile(profile)
102 verbosity_name = config.getoption(VERBOSITY_OPTION)
103 if verbosity_name:
104 verbosity_value = Verbosity[verbosity_name]
105 profile_name = "%s-with-%s-verbosity" % (
106 settings._current_profile,
107 verbosity_name,
108 )
109 # register_profile creates a new profile, exactly like the current one,
110 # with the extra values given (in this case 'verbosity')
111 settings.register_profile(profile_name, verbosity=verbosity_value)
112 settings.load_profile(profile_name)
113 seed = config.getoption(SEED_OPTION)
114 if seed is not None:
115 try:
116 seed = int(seed)
117 except ValueError:
118 pass
119 core.global_force_seed = seed
120 config.addinivalue_line("markers", "hypothesis: Tests which use hypothesis.")
122 @pytest.hookimpl(hookwrapper=True)
123 def pytest_runtest_call(item):
124 if not hasattr(item, "obj"):
125 yield
126 elif not is_hypothesis_test(item.obj):
127 # If @given was not applied, check whether other hypothesis
128 # decorators were applied, and raise an error if they were.
129 if getattr(item.obj, "is_hypothesis_strategy_function", False):
130 raise InvalidArgument(
131 "%s is a function that returns a Hypothesis strategy, but pytest "
132 "has collected it as a test function. This is useless as the "
133 "function body will never be executed. To define a test "
134 "function, use @given instead of @composite." % (item.nodeid,)
135 )
136 message = "Using `@%s` on a test without `@given` is completely pointless."
137 for name, attribute in [
138 ("example", "hypothesis_explicit_examples"),
139 ("seed", "_hypothesis_internal_use_seed"),
140 ("settings", "_hypothesis_internal_settings_applied"),
141 ("reproduce_example", "_hypothesis_internal_use_reproduce_failure"),
142 ]:
143 if hasattr(item.obj, attribute):
144 raise InvalidArgument(message % (name,))
145 yield
146 else:
147 if item.get_closest_marker("parametrize") is not None:
148 # Give every parametrized test invocation a unique database key
149 key = item.nodeid.encode("utf-8")
150 item.obj.hypothesis.inner_test._hypothesis_internal_add_digest = key
152 store = StoringReporter(item.config)
154 def note_statistics(stats):
155 lines = [item.nodeid + ":", ""] + stats.get_description() + [""]
156 item.hypothesis_statistics = lines
158 with collector.with_value(note_statistics):
159 with with_reporter(store):
160 yield
161 if store.results:
162 item.hypothesis_report_information = list(store.results)
164 @pytest.hookimpl(hookwrapper=True)
165 def pytest_runtest_makereport(item, call):
166 report = (yield).get_result()
167 if hasattr(item, "hypothesis_report_information"):
168 report.sections.append(
169 ("Hypothesis", "\n".join(item.hypothesis_report_information))
170 )
171 if hasattr(item, "hypothesis_statistics") and report.when == "teardown":
172 val = ("hypothesis-stats", item.hypothesis_statistics)
173 report.user_properties.append(val)
175 def pytest_terminal_summary(terminalreporter):
176 if not terminalreporter.config.getoption(PRINT_STATISTICS_OPTION):
177 return
178 terminalreporter.section("Hypothesis Statistics")
179 # terminalreporter.stats is a dict, where the empty string appears to
180 # always be the key for a list of _pytest.reports.TestReport objects
181 # (where we stored the statistics data in pytest_runtest_makereport above)
182 for test_report in terminalreporter.stats.get("", []):
183 for name, lines in test_report.user_properties:
184 if name == "hypothesis-stats" and test_report.when == "teardown":
185 for li in lines:
186 terminalreporter.write_line(li)
188 def pytest_collection_modifyitems(items):
189 for item in items:
190 if isinstance(item, pytest.Function) and is_hypothesis_test(item.obj):
191 item.add_marker("hypothesis")
194def load():
195 """Required for `pluggy` to load a plugin from setuptools entrypoints."""