Skip to content

Commit cbf7ea1

Browse files
authored
Merge pull request #4011 from jobh/reinstate-coverage
Reinstate coverage
2 parents 95e27a8 + c8d9798 commit cbf7ea1

File tree

10 files changed

+52
-10
lines changed

10 files changed

+52
-10
lines changed

hypothesis-python/.coveragerc

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
[run]
2+
parallel = True
23
branch = True
4+
source = hypothesis
35
omit =
46
**/_hypothesis_ftz_detector.py
57
**/_hypothesis_pytestplugin.py

hypothesis-python/RELEASE.rst

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
RELEASE_TYPE: patch
2+
3+
Fixes and reinstates full coverage of internal tests, which was accidentally
4+
disabled in :pull:`3935`.
5+
6+
Closes :issue:`4003`.

hypothesis-python/docs/strategies.rst

+20
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,26 @@ loading our pytest plugin from your ``conftest.py`` instead::
212212
echo "pytest_plugins = ['hypothesis.extra.pytestplugin']\n" > tests/conftest.py
213213
pytest -p "no:hypothesispytest" ...
214214

215+
Another alternative, which we in fact use in our CI self-tests because it works
216+
well also with parallel tests, is to automatically start coverage early for all
217+
new processes if an environment variable is set.
218+
This automatic starting is set up by the PyPi package :pypi:`coverage_enable_subprocess`.
219+
220+
This means all configuration must be done in ``.coveragerc``, and not on the
221+
command line::
222+
223+
[run]
224+
parallel = True
225+
source = ...
226+
227+
Then, set the relevant environment variable and run normally::
228+
229+
python -m pip install coverage_enable_subprocess
230+
export COVERAGE_PROCESS_START=$PATH/.coveragerc
231+
pytest [-n auto] ...
232+
coverage combine
233+
coverage report
234+
215235

216236
.. _alternative-backends:
217237

hypothesis-python/src/hypothesis/core.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1104,7 +1104,9 @@ def _execute_once_for_engine(self, data: ConjectureData) -> None:
11041104
if TESTCASE_CALLBACKS:
11051105
if runner := getattr(self, "_runner", None):
11061106
phase = runner._current_phase
1107-
elif self.failed_normally or self.failed_due_to_deadline:
1107+
elif (
1108+
self.failed_normally or self.failed_due_to_deadline
1109+
): # pragma: no cover # FIXME
11081110
phase = "shrink"
11091111
else: # pragma: no cover # in case of messing with internals
11101112
phase = "unknown"

hypothesis-python/src/hypothesis/extra/_patching.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def __call_node_to_example_dec(self, node, via):
121121
cst.Module([]).code_for_node(via),
122122
mode=black.FileMode(line_length=self.line_length),
123123
)
124-
except (ImportError, AttributeError):
124+
except (ImportError, AttributeError): # pragma: no cover
125125
return None # See https://github.com/psf/black/pull/4224
126126
via = cst.parse_expression(pretty.strip())
127127
return cst.Decorator(via)

hypothesis-python/src/hypothesis/internal/entropy.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ def my_WORKING_hook():
127127
"PRNG. See the docs for `register_random` for more "
128128
"details."
129129
)
130-
elif not FREE_THREADED_CPYTHON:
130+
elif not FREE_THREADED_CPYTHON: # pragma: no cover # FIXME
131131
# On CPython, check for the free-threaded build because
132132
# gc.get_referrers() ignores objects with immortal refcounts
133133
# and objects are immortalized in the Python 3.13

hypothesis-python/src/hypothesis/stateful.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ def _add_result_to_targets(self, targets, result):
388388
for target in targets:
389389
name = self._new_name(target)
390390

391-
def printer(obj, p, cycle, name=name):
391+
def printer(obj, p, cycle, name=name): # pragma: no cover # FIXME
392392
return p.text(name)
393393

394394
self.__printer.singleton_pprinters.setdefault(id(result), printer)

hypothesis-python/src/hypothesis/statistics.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def format_ms(times):
4848
"""
4949
ordered = sorted(times)
5050
n = len(ordered) - 1
51-
if n < 0 or any(math.isnan(t) for t in ordered):
51+
if n < 0 or any(math.isnan(t) for t in ordered): # pragma: no cover
5252
return "NaN ms"
5353
lower = int(ordered[int(math.floor(n * 0.05))] * 1000)
5454
upper = int(ordered[int(math.ceil(n * 0.95))] * 1000)

hypothesis-python/tests/cover/test_composite.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -196,19 +196,22 @@ def test_drawfn_cannot_be_instantiated():
196196

197197

198198
@pytest.mark.skipif(sys.version_info[:2] == (3, 9), reason="stack depth varies???")
199-
@pytest.mark.skipif(sys.version_info[:2] <= (3, 11), reason="TEMP: see PR #3961")
200199
def test_warns_on_strategy_annotation():
201200
# TODO: print the stack on Python 3.10 and 3.11 to determine the appropriate
202201
# stack depth to use. Consider adding a debug-print if IN_COVERAGE_TESTS
203202
# and the relevant depth is_hypothesis_file(), for easier future fixing.
203+
#
204+
# Meanwhile, the test is not skipped on 3.10/3.11 as it is still required for
205+
# coverage of the warning-generating branch.
204206
with pytest.warns(HypothesisWarning, match="Return-type annotation") as w:
205207

206208
@st.composite
207209
def my_integers(draw: st.DrawFn) -> st.SearchStrategy[int]:
208210
return draw(st.integers())
209211

210-
assert len(w.list) == 1
211-
assert w.list[0].filename == __file__ # check stacklevel points to user code
212+
if sys.version_info[:2] > (3, 11): # TEMP: see PR #3961
213+
assert len(w.list) == 1
214+
assert w.list[0].filename == __file__ # check stacklevel points to user code
212215

213216

214217
def test_composite_allows_overload_without_draw():

hypothesis-python/tox.ini

+11-2
Original file line numberDiff line numberDiff line change
@@ -218,20 +218,29 @@ allowlist_externals =
218218
setenv=
219219
PYTHONWARNDEFAULTENCODING=1
220220
HYPOTHESIS_INTERNAL_COVERAGE=true
221+
COVERAGE_PROCESS_START=.coveragerc
221222
commands_pre =
222223
rm -f branch-check*
223224
pip install .[zoneinfo]
225+
pip install coverage_enable_subprocess
226+
commands_post =
227+
pip uninstall -y coverage_enable_subprocess
224228
# Produce a coverage report even if the test suite fails.
225229
# (The tox task will still count as failed.)
226230
ignore_errors = true
231+
# We've had problems correctly measuring coverage using pytest-cov when running
232+
# in parallel, so instead we start coverage implicitly on all (sub-)processes by
233+
# way of the coverage_enable_subprocesses installation. This requires all options
234+
# to be set in .coveragerc (including source), but that's ok as it is overridden
235+
# by --cov=... in conjecture-coverage.
227236
commands =
228237
python -bb -X dev -m pytest -n auto --ff {posargs} \
229-
--cov=hypothesis.internal.conjecture --cov-config=.coveragerc \
230238
tests/cover tests/conjecture tests/datetime tests/numpy tests/pandas tests/lark \
231239
tests/redis tests/dpcontracts tests/codemods tests/typing_extensions tests/patching tests/test_annotated_types.py
240+
python -m coverage combine
241+
python -m coverage report
232242
python scripts/validate_branch_check.py
233243

234-
235244
[testenv:conjecture-coverage]
236245
deps =
237246
-r../requirements/coverage.txt

0 commit comments

Comments
 (0)