Skip to content

Commit 68a39a9

Browse files
committed
Fix pickle errors for exceptions
1 parent 4b1882c commit 68a39a9

File tree

6 files changed

+47
-11
lines changed

6 files changed

+47
-11
lines changed

hypothesis-python/RELEASE.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
RELEASE_TYPE: patch
2+
3+
This patch makes ``FailedHealthCheck`` and ``DeadlineExceeded`` exceptions
4+
picklable, for compatibility with Django's parallel test runner (:issue:`3426`).

hypothesis-python/src/hypothesis/errors.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,7 @@ class HypothesisWarning(HypothesisException, Warning):
9393

9494

9595
class FailedHealthCheck(_Trimmable):
96-
"""Raised when a test fails a preliminary healthcheck that occurs before
97-
execution."""
98-
99-
def __init__(self, message, check):
100-
super().__init__(message)
101-
self.health_check = check
96+
"""Raised when a test fails a healthcheck."""
10297

10398

10499
class NonInteractiveExampleWarning(HypothesisWarning):
@@ -149,6 +144,9 @@ def __init__(self, runtime, deadline):
149144
self.runtime = runtime
150145
self.deadline = deadline
151146

147+
def __reduce__(self):
148+
return (type(self), (self.runtime, self.deadline))
149+
152150

153151
class StopTest(BaseException):
154152
"""Raised when a test should stop running and return control to

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ def fail_health_check(settings, message, label):
2424
f"If you want to disable just this health check, add {label} "
2525
"to the suppress_health_check settings for this test."
2626
)
27-
raise FailedHealthCheck(message, label)
27+
raise FailedHealthCheck(message)

hypothesis-python/tests/conjecture/test_engine.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ def accept(f):
404404

405405
with pytest.raises(FailedHealthCheck) as e:
406406
runner.run()
407-
assert e.value.health_check == label
407+
assert str(label) in str(e.value)
408408
assert not runner.interesting_examples
409409

410410
return accept

hypothesis-python/tests/cover/test_health_checks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ def test(b):
176176
with pytest.raises(FailedHealthCheck) as exc:
177177
test()
178178

179-
assert exc.value.health_check == HealthCheck.large_base_example
179+
assert str(HealthCheck.large_base_example) in str(exc.value)
180180

181181

182182
def test_example_that_shrinks_to_overrun_fails_health_check():
@@ -187,7 +187,7 @@ def test(b):
187187
with pytest.raises(FailedHealthCheck) as exc:
188188
test()
189189

190-
assert exc.value.health_check == HealthCheck.large_base_example
190+
assert str(HealthCheck.large_base_example) in str(exc.value)
191191

192192

193193
def test_it_is_an_error_to_suppress_non_iterables():

hypothesis-python/tests/cover/test_regressions.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,22 @@
88
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
99
# obtain one at https://mozilla.org/MPL/2.0/.
1010

11+
import pickle
1112
import random
13+
from datetime import timedelta
1214
from unittest.mock import Mock
1315

1416
import pytest
1517

16-
from hypothesis import Verbosity, assume, given, seed, settings, strategies as st
18+
from hypothesis import (
19+
Verbosity,
20+
assume,
21+
errors,
22+
given,
23+
seed,
24+
settings,
25+
strategies as st,
26+
)
1727

1828

1929
def strat():
@@ -111,3 +121,27 @@ def test_prng_state_unpolluted_by_given_issue_1266():
111121
assert second == third
112122
else:
113123
assert second != third
124+
125+
126+
exc_instances = [
127+
errors.NoSuchExample("foobar", extra="baz"),
128+
errors.DeadlineExceeded(
129+
runtime=timedelta(seconds=1.5), deadline=timedelta(seconds=1.0)
130+
),
131+
]
132+
133+
134+
@pytest.mark.parametrize("exc", exc_instances, ids=repr)
135+
def test_exceptions_are_picklable(exc):
136+
# See https://github.com/HypothesisWorks/hypothesis/issues/3426
137+
pickle.loads(pickle.dumps(exc))
138+
139+
140+
def test_no_missed_custom_init_exceptions():
141+
untested_errors_with_custom_init = {
142+
et
143+
for et in vars(errors).values()
144+
if isinstance(et, type) and issubclass(et, Exception) and "__init__" in vars(et)
145+
} - {type(exc) for exc in exc_instances}
146+
print(untested_errors_with_custom_init)
147+
assert not untested_errors_with_custom_init

0 commit comments

Comments
 (0)