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

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

96 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__( 

38 self, reason: str | None = None, *, location: str | None = None 

39 ) -> None: 

40 self.reason = reason 

41 # "filename:lineno" of the failing assume() or reject() call, if known 

42 self.location = location 

43 

44 

45class NoSuchExample(HypothesisException): 

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

47 

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

49 unable to find one. 

50 """ 

51 

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

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

54 

55 

56class Unsatisfiable(_Trimmable): 

57 """We ran out of test cases before we could find enough which satisfy the 

58 assumptions of this hypothesis. 

59 

60 This could be because the function is using |assume| in a way that is 

61 too hard to satisfy. If so, try writing a custom strategy or using a 

62 better starting point (e.g if you are requiring a list has unique 

63 values you could instead filter out all duplicate values from the list) 

64 """ 

65 

66 

67class ChoiceTooLarge(HypothesisException): 

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

69 

70 

71class CannotInvert(HypothesisException): 

72 """ 

73 Internal error raised by SearchStrategy._invert, either because the value 

74 is not produced by that strategy, or because we haven't implemented an 

75 inversion for it. 

76 """ 

77 

78 

79class Flaky(_Trimmable): 

80 """ 

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

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

83 

84 .. seealso:: 

85 

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

87 """ 

88 

89 

90class FlakyReplay(Flaky): 

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

92 detected during replay. 

93 

94 Carries information allowing the runner to reconstruct the flakiness as 

95 a FlakyFailure exception group for final presentation. 

96 """ 

97 

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

99 super().__init__(reason) 

100 self.reason = reason 

101 self._interesting_origins = interesting_origins 

102 

103 

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

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

106 return ", ".join( 

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

108 ) 

109 

110 

111class FlakyStrategyDefinition(Flaky): 

112 """ 

113 This function appears to cause inconsistent data generation. 

114 

115 Common causes for this problem are: 

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

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

118 relevant state in from Hypothesis. 

119 

120 .. seealso:: 

121 

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

123 """ 

124 

125 _BASE_MESSAGE = ( 

126 "Inconsistent data generation! Data generation behaved differently " 

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

128 "state?" 

129 ) 

130 

131 @classmethod 

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

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

134 

135 @classmethod 

136 def from_mismatch( 

137 cls, 

138 expected_type: str, 

139 expected_constraints: ChoiceConstraintsT, 

140 actual_type: str, 

141 actual_constraints: ChoiceConstraintsT, 

142 ) -> "FlakyStrategyDefinition": 

143 if actual_type != expected_type: 

144 detail = ( 

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

146 f" first: {expected_type}\n" 

147 f" second: {actual_type}\n" 

148 ) 

149 else: 

150 detail = ( 

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

152 "than the first.\n" 

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

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

155 ) 

156 return cls.with_detail(detail) 

157 

158 

159class _WrappedBaseException(Exception): 

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

161 

162 

163class FlakyFailure(ExceptionGroup, Flaky): 

164 """ 

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

166 fail when passed this value at least once, but a subsequent invocation 

167 did not fail, or caused a distinct error. 

168 

169 Common causes for this problem are: 

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

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

172 relevant state in from Hypothesis. 

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

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

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

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

177 don't do that and testing those instead. 

178 

179 .. seealso:: 

180 

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

182 """ 

183 

184 def __new__(cls, msg, group): 

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

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

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

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

189 group = list(group) 

190 for i, exc in enumerate(group): 

191 if not isinstance(exc, Exception): 

192 err = _WrappedBaseException() 

193 err.__cause__ = err.__context__ = exc 

194 group[i] = err 

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

196 

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

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

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

200 def derive(self, excs): 

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

202 

203 

204class FlakyBackendFailure(FlakyFailure): 

205 """ 

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

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

208 

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

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

211 does not reproduce, Hypothesis raises this exception. 

212 """ 

213 

214 

215class InvalidArgument(_Trimmable, TypeError): 

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

217 some manner incorrect.""" 

218 

219 

220class ResolutionFailed(InvalidArgument): 

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

222 

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

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

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

226 """ 

227 

228 

229class InvalidState(HypothesisException): 

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

231 

232 

233class InvalidDefinition(_Trimmable, TypeError): 

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

235 has something wrong with it.""" 

236 

237 

238class HypothesisWarning(HypothesisException, Warning): 

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

240 

241 

242class FailedHealthCheck(_Trimmable): 

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

244 

245 

246class NonInteractiveExampleWarning(HypothesisWarning): 

247 """ 

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

249 

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

251 part of a test suite. 

252 """ 

253 

254 

255class HypothesisDeprecationWarning(HypothesisWarning, FutureWarning): 

256 """A deprecation warning issued by Hypothesis. 

257 

258 Actually inherits from FutureWarning, because DeprecationWarning is 

259 hidden by the default warnings filter. 

260 

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

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

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

264 """ 

265 

266 

267class HypothesisSideeffectWarning(HypothesisWarning): 

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

269 discouraged at import or initialization time because they are 

270 slow or have user-visible side effects. 

271 """ 

272 

273 

274class Frozen(HypothesisException): 

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

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

277 

278 

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

280 if name == "MultipleFailures": 

281 from hypothesis.internal.compat import BaseExceptionGroup 

282 from hypothesis.utils.deprecation import note_deprecation 

283 

284 note_deprecation( 

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

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

287 since="2022-08-02", 

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

289 stacklevel=1, 

290 ) 

291 return BaseExceptionGroup 

292 

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

294 

295 

296class DeadlineExceeded(_Trimmable): 

297 """ 

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

299 setting. 

300 """ 

301 

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

303 super().__init__( 

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

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

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

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

308 ) 

309 self.runtime = runtime 

310 self.deadline = deadline 

311 

312 def __reduce__( 

313 self, 

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

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

316 

317 

318class StopTest(BaseException): 

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

320 the Hypothesis engine, which should then continue normally. 

321 """ 

322 

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

324 super().__init__(repr(testcounter)) 

325 self.testcounter = testcounter 

326 

327 

328class DidNotReproduce(HypothesisException): 

329 pass 

330 

331 

332class Found(HypothesisException): 

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

334 

335 

336class RewindRecursive(Exception): 

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

338 

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

340 self.target = target 

341 

342 

343class SmallSearchSpaceWarning(HypothesisWarning): 

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

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

346 

347 

348class NonRoundTrippableCharactersWarning(HypothesisWarning): 

349 """Issued when the ``codec`` argument to 

350 :func:`~hypothesis.strategies.characters` allows generating characters 

351 which encode successfully, but do not decode back to the same character. 

352 

353 Pass each such character in either ``include_characters`` or 

354 ``exclude_characters`` to silence this warning. 

355 """ 

356 

357 

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

359_valid_cannot_proceed_scopes = CannotProceedScopeT.__args__ # type: ignore 

360 

361 

362class BackendCannotProceed(HypothesisException): 

363 """ 

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

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

366 symbolic execution perhaps in |PrimitiveProvider.realize|. 

367 

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

369 

370 verified: 

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

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

373 Hypothesis will report unsound verification in the backend too. 

374 

375 exhausted: 

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

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

378 native code blocks symbolic reasoning very early. 

379 

380 discard_test_case: 

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

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

383 this backend. 

384 """ 

385 

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

387 if scope not in _valid_cannot_proceed_scopes: 

388 raise InvalidArgument( 

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

390 f"{_valid_cannot_proceed_scopes!r}" 

391 ) 

392 self.scope = scope