Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/hypothesis/errors.py: 66%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x 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# Copyright the Hypothesis Authors.
5# Individual contributors are listed in AUTHORS.rst and the git log.
6#
7# This Source Code Form is subject to the terms of the Mozilla Public License,
8# v. 2.0. If a copy of the MPL was not distributed with this file, You can
9# obtain one at https://mozilla.org/MPL/2.0/.
11from collections.abc import Mapping
12from datetime import timedelta
13from typing import TYPE_CHECKING, Any, Literal
15if TYPE_CHECKING:
16 from hypothesis.internal.conjecture.choice import ChoiceConstraintsT
17else:
18 ChoiceConstraintsT = Mapping
21class HypothesisException(Exception):
22 """Generic parent class for exceptions thrown by Hypothesis."""
25class _Trimmable(HypothesisException):
26 """Hypothesis can trim these tracebacks even if they're raised internally."""
29class UnsatisfiedAssumption(HypothesisException):
30 """An internal error raised by assume.
32 If you're seeing this error something has gone wrong.
33 """
35 def __init__(
36 self, reason: str | None = None, *, location: str | None = None
37 ) -> None:
38 self.reason = reason
39 # "filename:lineno" of the failing assume() or reject() call, if known
40 self.location = location
43class NoSuchExample(HypothesisException):
44 """The condition we have been asked to satisfy appears to be always false.
46 This does not guarantee that no example exists, only that we were
47 unable to find one.
48 """
50 def __init__(self, condition_string: str, extra: str = "") -> None:
51 super().__init__(f"No examples found of condition {condition_string}{extra}")
54class Unsatisfiable(_Trimmable):
55 """We ran out of test cases before we could find enough which satisfy the
56 assumptions of this hypothesis.
58 This could be because the function is using |assume| in a way that is
59 too hard to satisfy. If so, try writing a custom strategy or using a
60 better starting point (e.g if you are requiring a list has unique
61 values you could instead filter out all duplicate values from the list)
62 """
65class ChoiceTooLarge(HypothesisException):
66 """An internal error raised by choice_from_index."""
69class CannotInvert(HypothesisException):
70 """
71 Internal error raised by SearchStrategy._invert, either because the value
72 is not produced by that strategy, or because we haven't implemented an
73 inversion for it.
74 """
77class Flaky(_Trimmable):
78 """
79 Base class for indeterministic failures. Usually one of the more
80 specific subclasses (|FlakyFailure| or |FlakyStrategyDefinition|) is raised.
82 .. seealso::
84 See also the :doc:`flaky failures tutorial </tutorial/flaky>`.
85 """
88class FlakyReplay(Flaky):
89 """Internal error raised by the conjecture engine if flaky failures are
90 detected during replay.
92 Carries information allowing the runner to reconstruct the flakiness as
93 a FlakyFailure exception group for final presentation.
94 """
96 def __init__(self, reason, interesting_origins=None):
97 super().__init__(reason)
98 self.reason = reason
99 self._interesting_origins = interesting_origins
102def _render_constraints(show: Mapping[str, object], other: Mapping[str, object]) -> str:
103 assert show.keys() == other.keys()
104 return ", ".join(
105 f"{k}={'...' if v == other[k] else repr(v)}" for k, v in show.items()
106 )
109class FlakyStrategyDefinition(Flaky):
110 """
111 This function appears to cause inconsistent data generation.
113 Common causes for this problem are:
114 1. The strategy depends on external state. e.g. it uses an external
115 random number generator. Try to make a version that passes all the
116 relevant state in from Hypothesis.
118 .. seealso::
120 See also the :doc:`flaky failures tutorial </tutorial/flaky>`.
121 """
123 _BASE_MESSAGE = (
124 "Inconsistent data generation! Data generation behaved differently "
125 "between test cases. Is your data generation depending on external "
126 "state?"
127 )
129 @classmethod
130 def with_detail(cls, detail: str) -> "FlakyStrategyDefinition":
131 return cls(f"{cls._BASE_MESSAGE}\n\n{detail}")
133 @classmethod
134 def from_mismatch(
135 cls,
136 expected_type: str,
137 expected_constraints: ChoiceConstraintsT,
138 actual_type: str,
139 actual_constraints: ChoiceConstraintsT,
140 ) -> "FlakyStrategyDefinition":
141 if actual_type != expected_type:
142 detail = (
143 "The second test case drew a different type of value than the first.\n"
144 f" first: {expected_type}\n"
145 f" second: {actual_type}\n"
146 )
147 else:
148 detail = (
149 f"The second test case drew type {actual_type} with different constraints "
150 "than the first.\n"
151 f" first: {_render_constraints(expected_constraints, actual_constraints)}\n"
152 f" second: {_render_constraints(actual_constraints, expected_constraints)}\n"
153 )
154 return cls.with_detail(detail)
157class _WrappedBaseException(Exception):
158 """Used internally for wrapping BaseExceptions as components of FlakyFailure."""
161class FlakyFailure(ExceptionGroup, Flaky):
162 """
163 This function appears to fail non-deterministically: We have seen it
164 fail when passed this value at least once, but a subsequent invocation
165 did not fail, or caused a distinct error.
167 Common causes for this problem are:
168 1. The function depends on external state. e.g. it uses an external
169 random number generator. Try to make a version that passes all the
170 relevant state in from Hypothesis.
171 2. The function is suffering from too much recursion and its failure
172 depends sensitively on where it's been called from.
173 3. The function is timing sensitive and can fail or pass depending on
174 how long it takes. Try breaking it up into smaller functions which
175 don't do that and testing those instead.
177 .. seealso::
179 See also the :doc:`flaky failures tutorial </tutorial/flaky>`.
180 """
182 def __new__(cls, msg, group):
183 # The Exception mixin forces this an ExceptionGroup (only accepting
184 # Exceptions, not BaseException). Usually BaseException is raised
185 # directly and will hence not be part of a FlakyFailure, but I'm not
186 # sure this assumption holds everywhere. So wrap any BaseExceptions.
187 group = list(group)
188 for i, exc in enumerate(group):
189 if not isinstance(exc, Exception):
190 err = _WrappedBaseException()
191 err.__cause__ = err.__context__ = exc
192 group[i] = err
193 return ExceptionGroup.__new__(cls, msg, group)
195 # defining `derive` is required for `split` to return an instance of FlakyFailure
196 # instead of ExceptionGroup. See https://github.com/python/cpython/issues/119287
197 # and https://docs.python.org/3/library/exceptions.html#BaseExceptionGroup.derive
198 def derive(self, excs):
199 return type(self)(self.message, excs)
202class FlakyBackendFailure(FlakyFailure):
203 """
204 A failure was reported by an |alternative backend|,
205 but this failure did not reproduce when replayed under the Hypothesis backend.
207 When an alternative backend reports a failure, Hypothesis first replays it
208 under the standard Hypothesis backend to check for flakiness. If the failure
209 does not reproduce, Hypothesis raises this exception.
210 """
213class InvalidArgument(_Trimmable, TypeError):
214 """Used to indicate that the arguments to a Hypothesis function were in
215 some manner incorrect."""
218class ResolutionFailed(InvalidArgument):
219 """Hypothesis had to resolve a type to a strategy, but this failed.
221 Type inference is best-effort, so this only happens when an
222 annotation exists but could not be resolved for a required argument
223 to the target of ``builds()``, or where the user passed ``...``.
224 """
227class InvalidState(HypothesisException):
228 """The system is not in a state where you were allowed to do that."""
231class InvalidDefinition(_Trimmable, TypeError):
232 """Used to indicate that a class definition was not well put together and
233 has something wrong with it."""
236class HypothesisWarning(HypothesisException, Warning):
237 """A generic warning issued by Hypothesis."""
240class FailedHealthCheck(_Trimmable):
241 """Raised when a test fails a health check. See |HealthCheck|."""
244class NonInteractiveExampleWarning(HypothesisWarning):
245 """
246 Emitted when |.example| is used outside of interactive use.
248 |.example| is intended for exploratory and interactive work, not to be run as
249 part of a test suite.
250 """
253class HypothesisDeprecationWarning(HypothesisWarning, FutureWarning):
254 """A deprecation warning issued by Hypothesis.
256 Actually inherits from FutureWarning, because DeprecationWarning is
257 hidden by the default warnings filter.
259 You can configure the :mod:`python:warnings` module to handle these
260 warnings differently to others, either turning them into errors or
261 suppressing them entirely. Obviously we would prefer the former!
262 """
265class HypothesisSideeffectWarning(HypothesisWarning):
266 """A warning issued by Hypothesis when it sees actions that are
267 discouraged at import or initialization time because they are
268 slow or have user-visible side effects.
269 """
272class Frozen(HypothesisException):
273 """Raised when a mutation method has been called on a ConjectureData object
274 after freeze() has been called."""
277def __getattr__(name: str) -> Any:
278 if name == "MultipleFailures":
279 from hypothesis.utils.deprecation import note_deprecation
281 note_deprecation(
282 "MultipleFailures is deprecated; use the builtin `BaseExceptionGroup` type instead",
283 since="2022-08-02",
284 has_codemod=False, # This would be a great PR though!
285 stacklevel=1,
286 )
287 return BaseExceptionGroup
289 raise AttributeError(f"Module 'hypothesis.errors' has no attribute {name}")
292class DeadlineExceeded(_Trimmable):
293 """
294 Raised when an input takes too long to run, relative to the |settings.deadline|
295 setting.
296 """
298 def __init__(self, runtime: timedelta, deadline: timedelta) -> None:
299 super().__init__(
300 f"Test took {runtime.total_seconds() * 1000:.2f}ms, which exceeds "
301 f"the deadline of {deadline.total_seconds() * 1000:.2f}ms. If you "
302 "expect test cases to take this long, you can use @settings(deadline=...) "
303 "to either set a higher deadline, or to disable it with deadline=None."
304 )
305 self.runtime = runtime
306 self.deadline = deadline
308 def __reduce__(
309 self,
310 ) -> tuple[type["DeadlineExceeded"], tuple[timedelta, timedelta]]:
311 return (type(self), (self.runtime, self.deadline))
314class StopTest(BaseException):
315 """Raised when a test should stop running and return control to
316 the Hypothesis engine, which should then continue normally.
317 """
319 def __init__(self, testcounter: int) -> None:
320 super().__init__(repr(testcounter))
321 self.testcounter = testcounter
324class DidNotReproduce(HypothesisException):
325 pass
328class Found(HypothesisException):
329 """Signal that the example matches condition. Internal use only."""
332class RewindRecursive(Exception):
333 """Signal that the type inference should be rewound due to recursive types. Internal use only."""
335 def __init__(self, target: object) -> None:
336 self.target = target
339class SmallSearchSpaceWarning(HypothesisWarning):
340 """Indicates that an inferred strategy does not span the search space
341 in a meaningful way, for example by only creating default instances."""
344class NonRoundTrippableCharactersWarning(HypothesisWarning):
345 """Issued when the ``codec`` argument to
346 :func:`~hypothesis.strategies.characters` allows generating characters
347 which encode successfully, but do not decode back to the same character.
349 Pass each such character in either ``include_characters`` or
350 ``exclude_characters`` to silence this warning.
351 """
354CannotProceedScopeT = Literal["verified", "exhausted", "discard_test_case", "other"]
355_valid_cannot_proceed_scopes = CannotProceedScopeT.__args__ # type: ignore
358class BackendCannotProceed(HypothesisException):
359 """
360 Raised by alternative backends when a |PrimitiveProvider| cannot proceed.
361 This is expected to occur inside one of the ``.draw_*()`` methods, or for
362 symbolic execution perhaps in |PrimitiveProvider.realize|.
364 The optional ``scope`` argument can enable smarter integration:
366 verified:
367 Do not request further |test cases| from this backend. We *may*
368 generate more test cases with other backends; if one fails then
369 Hypothesis will report unsound verification in the backend too.
371 exhausted:
372 Do not request further test cases from this backend; finish testing
373 with test cases generated with the default backend. Common if e.g.
374 native code blocks symbolic reasoning very early.
376 discard_test_case:
377 This particular test case could not be converted to concrete values;
378 skip any further processing and continue with another test case from
379 this backend.
380 """
382 def __init__(self, scope: CannotProceedScopeT = "other", /) -> None:
383 if scope not in _valid_cannot_proceed_scopes:
384 raise InvalidArgument(
385 f"Got scope={scope}, but expected one of "
386 f"{_valid_cannot_proceed_scopes!r}"
387 )
388 self.scope = scope