Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/hypothesis/errors.py: 63%

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

93 statements  

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/. 

10 

11from collections.abc import Mapping 

12from datetime import timedelta 

13from typing import TYPE_CHECKING, Any, Literal 

14 

15from hypothesis.internal.compat import ExceptionGroup 

16 

17if TYPE_CHECKING: 

18 from hypothesis.internal.conjecture.choice import ChoiceConstraintsT 

19else: 

20 ChoiceConstraintsT = Mapping 

21 

22 

23class HypothesisException(Exception): 

24 """Generic parent class for exceptions thrown by Hypothesis.""" 

25 

26 

27class _Trimmable(HypothesisException): 

28 """Hypothesis can trim these tracebacks even if they're raised internally.""" 

29 

30 

31class UnsatisfiedAssumption(HypothesisException): 

32 """An internal error raised by assume. 

33 

34 If you're seeing this error something has gone wrong. 

35 """ 

36 

37 def __init__(self, reason: str | None = None) -> None: 

38 self.reason = reason 

39 

40 

41class NoSuchExample(HypothesisException): 

42 """The condition we have been asked to satisfy appears to be always false. 

43 

44 This does not guarantee that no example exists, only that we were 

45 unable to find one. 

46 """ 

47 

48 def __init__(self, condition_string: str, extra: str = "") -> None: 

49 super().__init__(f"No examples found of condition {condition_string}{extra}") 

50 

51 

52class Unsatisfiable(_Trimmable): 

53 """We ran out of time or examples before we could find enough examples 

54 which satisfy the assumptions of this hypothesis. 

55 

56 This could be because the function is too slow. If so, try upping 

57 the timeout. It could also be because the function is using assume 

58 in a way that is too hard to satisfy. If so, try writing a custom 

59 strategy or using a better starting point (e.g if you are requiring 

60 a list has unique values you could instead filter out all duplicate 

61 values from the list) 

62 """ 

63 

64 

65class ChoiceTooLarge(HypothesisException): 

66 """An internal error raised by choice_from_index.""" 

67 

68 

69class Flaky(_Trimmable): 

70 """ 

71 Base class for indeterministic failures. Usually one of the more 

72 specific subclasses (|FlakyFailure| or |FlakyStrategyDefinition|) is raised. 

73 

74 .. seealso:: 

75 

76 See also the :doc:`flaky failures tutorial </tutorial/flaky>`. 

77 """ 

78 

79 

80class FlakyReplay(Flaky): 

81 """Internal error raised by the conjecture engine if flaky failures are 

82 detected during replay. 

83 

84 Carries information allowing the runner to reconstruct the flakiness as 

85 a FlakyFailure exception group for final presentation. 

86 """ 

87 

88 def __init__(self, reason, interesting_origins=None): 

89 super().__init__(reason) 

90 self.reason = reason 

91 self._interesting_origins = interesting_origins 

92 

93 

94def _render_constraints(show: Mapping[str, object], other: Mapping[str, object]) -> str: 

95 assert show.keys() == other.keys() 

96 return ", ".join( 

97 f"{k}={'...' if v == other[k] else repr(v)}" for k, v in show.items() 

98 ) 

99 

100 

101class FlakyStrategyDefinition(Flaky): 

102 """ 

103 This function appears to cause inconsistent data generation. 

104 

105 Common causes for this problem are: 

106 1. The strategy depends on external state. e.g. it uses an external 

107 random number generator. Try to make a version that passes all the 

108 relevant state in from Hypothesis. 

109 

110 .. seealso:: 

111 

112 See also the :doc:`flaky failures tutorial </tutorial/flaky>`. 

113 """ 

114 

115 _BASE_MESSAGE = ( 

116 "Inconsistent data generation! Data generation behaved differently " 

117 "between test cases. Is your data generation depending on external " 

118 "state?" 

119 ) 

120 

121 @classmethod 

122 def with_detail(cls, detail: str) -> "FlakyStrategyDefinition": 

123 return cls(f"{cls._BASE_MESSAGE}\n\n{detail}") 

124 

125 @classmethod 

126 def from_mismatch( 

127 cls, 

128 expected_type: str, 

129 expected_constraints: ChoiceConstraintsT, 

130 actual_type: str, 

131 actual_constraints: ChoiceConstraintsT, 

132 ) -> "FlakyStrategyDefinition": 

133 if actual_type != expected_type: 

134 detail = ( 

135 "The second test case drew a different type of value than the first.\n" 

136 f" first: {expected_type}\n" 

137 f" second: {actual_type}\n" 

138 ) 

139 else: 

140 detail = ( 

141 f"The second test case drew type {actual_type} with different constraints " 

142 "than the first.\n" 

143 f" first: {_render_constraints(expected_constraints, actual_constraints)}\n" 

144 f" second: {_render_constraints(actual_constraints, expected_constraints)}\n" 

145 ) 

146 return cls.with_detail(detail) 

147 

148 

149class _WrappedBaseException(Exception): 

150 """Used internally for wrapping BaseExceptions as components of FlakyFailure.""" 

151 

152 

153class FlakyFailure(ExceptionGroup, Flaky): 

154 """ 

155 This function appears to fail non-deterministically: We have seen it 

156 fail when passed this example at least once, but a subsequent invocation 

157 did not fail, or caused a distinct error. 

158 

159 Common causes for this problem are: 

160 1. The function depends on external state. e.g. it uses an external 

161 random number generator. Try to make a version that passes all the 

162 relevant state in from Hypothesis. 

163 2. The function is suffering from too much recursion and its failure 

164 depends sensitively on where it's been called from. 

165 3. The function is timing sensitive and can fail or pass depending on 

166 how long it takes. Try breaking it up into smaller functions which 

167 don't do that and testing those instead. 

168 

169 .. seealso:: 

170 

171 See also the :doc:`flaky failures tutorial </tutorial/flaky>`. 

172 """ 

173 

174 def __new__(cls, msg, group): 

175 # The Exception mixin forces this an ExceptionGroup (only accepting 

176 # Exceptions, not BaseException). Usually BaseException is raised 

177 # directly and will hence not be part of a FlakyFailure, but I'm not 

178 # sure this assumption holds everywhere. So wrap any BaseExceptions. 

179 group = list(group) 

180 for i, exc in enumerate(group): 

181 if not isinstance(exc, Exception): 

182 err = _WrappedBaseException() 

183 err.__cause__ = err.__context__ = exc 

184 group[i] = err 

185 return ExceptionGroup.__new__(cls, msg, group) 

186 

187 # defining `derive` is required for `split` to return an instance of FlakyFailure 

188 # instead of ExceptionGroup. See https://github.com/python/cpython/issues/119287 

189 # and https://docs.python.org/3/library/exceptions.html#BaseExceptionGroup.derive 

190 def derive(self, excs): 

191 return type(self)(self.message, excs) 

192 

193 

194class FlakyBackendFailure(FlakyFailure): 

195 """ 

196 A failure was reported by an |alternative backend|, 

197 but this failure did not reproduce when replayed under the Hypothesis backend. 

198 

199 When an alternative backend reports a failure, Hypothesis first replays it 

200 under the standard Hypothesis backend to check for flakiness. If the failure 

201 does not reproduce, Hypothesis raises this exception. 

202 """ 

203 

204 

205class InvalidArgument(_Trimmable, TypeError): 

206 """Used to indicate that the arguments to a Hypothesis function were in 

207 some manner incorrect.""" 

208 

209 

210class ResolutionFailed(InvalidArgument): 

211 """Hypothesis had to resolve a type to a strategy, but this failed. 

212 

213 Type inference is best-effort, so this only happens when an 

214 annotation exists but could not be resolved for a required argument 

215 to the target of ``builds()``, or where the user passed ``...``. 

216 """ 

217 

218 

219class InvalidState(HypothesisException): 

220 """The system is not in a state where you were allowed to do that.""" 

221 

222 

223class InvalidDefinition(_Trimmable, TypeError): 

224 """Used to indicate that a class definition was not well put together and 

225 has something wrong with it.""" 

226 

227 

228class HypothesisWarning(HypothesisException, Warning): 

229 """A generic warning issued by Hypothesis.""" 

230 

231 

232class FailedHealthCheck(_Trimmable): 

233 """Raised when a test fails a health check. See |HealthCheck|.""" 

234 

235 

236class NonInteractiveExampleWarning(HypothesisWarning): 

237 """ 

238 Emitted when |.example| is used outside of interactive use. 

239 

240 |.example| is intended for exploratory and interactive work, not to be run as 

241 part of a test suite. 

242 """ 

243 

244 

245class HypothesisDeprecationWarning(HypothesisWarning, FutureWarning): 

246 """A deprecation warning issued by Hypothesis. 

247 

248 Actually inherits from FutureWarning, because DeprecationWarning is 

249 hidden by the default warnings filter. 

250 

251 You can configure the :mod:`python:warnings` module to handle these 

252 warnings differently to others, either turning them into errors or 

253 suppressing them entirely. Obviously we would prefer the former! 

254 """ 

255 

256 

257class HypothesisSideeffectWarning(HypothesisWarning): 

258 """A warning issued by Hypothesis when it sees actions that are 

259 discouraged at import or initialization time because they are 

260 slow or have user-visible side effects. 

261 """ 

262 

263 

264class Frozen(HypothesisException): 

265 """Raised when a mutation method has been called on a ConjectureData object 

266 after freeze() has been called.""" 

267 

268 

269def __getattr__(name: str) -> Any: 

270 if name == "MultipleFailures": 

271 from hypothesis.internal.compat import BaseExceptionGroup 

272 from hypothesis.utils.deprecation import note_deprecation 

273 

274 note_deprecation( 

275 "MultipleFailures is deprecated; use the builtin `BaseExceptionGroup` type " 

276 "instead, or `exceptiongroup.BaseExceptionGroup` before Python 3.11", 

277 since="2022-08-02", 

278 has_codemod=False, # This would be a great PR though! 

279 stacklevel=1, 

280 ) 

281 return BaseExceptionGroup 

282 

283 raise AttributeError(f"Module 'hypothesis.errors' has no attribute {name}") 

284 

285 

286class DeadlineExceeded(_Trimmable): 

287 """ 

288 Raised when an input takes too long to run, relative to the |settings.deadline| 

289 setting. 

290 """ 

291 

292 def __init__(self, runtime: timedelta, deadline: timedelta) -> None: 

293 super().__init__( 

294 f"Test took {runtime.total_seconds() * 1000:.2f}ms, which exceeds " 

295 f"the deadline of {deadline.total_seconds() * 1000:.2f}ms. If you " 

296 "expect test cases to take this long, you can use @settings(deadline=...) " 

297 "to either set a higher deadline, or to disable it with deadline=None." 

298 ) 

299 self.runtime = runtime 

300 self.deadline = deadline 

301 

302 def __reduce__( 

303 self, 

304 ) -> tuple[type["DeadlineExceeded"], tuple[timedelta, timedelta]]: 

305 return (type(self), (self.runtime, self.deadline)) 

306 

307 

308class StopTest(BaseException): 

309 """Raised when a test should stop running and return control to 

310 the Hypothesis engine, which should then continue normally. 

311 """ 

312 

313 def __init__(self, testcounter: int) -> None: 

314 super().__init__(repr(testcounter)) 

315 self.testcounter = testcounter 

316 

317 

318class DidNotReproduce(HypothesisException): 

319 pass 

320 

321 

322class Found(HypothesisException): 

323 """Signal that the example matches condition. Internal use only.""" 

324 

325 

326class RewindRecursive(Exception): 

327 """Signal that the type inference should be rewound due to recursive types. Internal use only.""" 

328 

329 def __init__(self, target: object) -> None: 

330 self.target = target 

331 

332 

333class SmallSearchSpaceWarning(HypothesisWarning): 

334 """Indicates that an inferred strategy does not span the search space 

335 in a meaningful way, for example by only creating default instances.""" 

336 

337 

338CannotProceedScopeT = Literal["verified", "exhausted", "discard_test_case", "other"] 

339_valid_cannot_proceed_scopes = CannotProceedScopeT.__args__ # type: ignore 

340 

341 

342class BackendCannotProceed(HypothesisException): 

343 """ 

344 Raised by alternative backends when a |PrimitiveProvider| cannot proceed. 

345 This is expected to occur inside one of the ``.draw_*()`` methods, or for 

346 symbolic execution perhaps in |PrimitiveProvider.realize|. 

347 

348 The optional ``scope`` argument can enable smarter integration: 

349 

350 verified: 

351 Do not request further test cases from this backend. We *may* 

352 generate more test cases with other backends; if one fails then 

353 Hypothesis will report unsound verification in the backend too. 

354 

355 exhausted: 

356 Do not request further test cases from this backend; finish testing 

357 with test cases generated with the default backend. Common if e.g. 

358 native code blocks symbolic reasoning very early. 

359 

360 discard_test_case: 

361 This particular test case could not be converted to concrete values; 

362 skip any further processing and continue with another test case from 

363 this backend. 

364 """ 

365 

366 def __init__(self, scope: CannotProceedScopeT = "other", /) -> None: 

367 if scope not in _valid_cannot_proceed_scopes: 

368 raise InvalidArgument( 

369 f"Got scope={scope}, but expected one of " 

370 f"{_valid_cannot_proceed_scopes!r}" 

371 ) 

372 self.scope = scope