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

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

76 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 datetime import timedelta 

12from typing import Any, Literal 

13 

14from hypothesis.internal.compat import ExceptionGroup 

15 

16 

17class HypothesisException(Exception): 

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

19 

20 

21class _Trimmable(HypothesisException): 

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

23 

24 

25class UnsatisfiedAssumption(HypothesisException): 

26 """An internal error raised by assume. 

27 

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

29 """ 

30 

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

32 self.reason = reason 

33 

34 

35class NoSuchExample(HypothesisException): 

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

37 

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

39 unable to find one. 

40 """ 

41 

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

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

44 

45 

46class Unsatisfiable(_Trimmable): 

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

48 which satisfy the assumptions of this hypothesis. 

49 

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

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

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

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

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

55 values from the list) 

56 """ 

57 

58 

59class ChoiceTooLarge(HypothesisException): 

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

61 

62 

63class Flaky(_Trimmable): 

64 """ 

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

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

67 

68 .. seealso:: 

69 

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

71 """ 

72 

73 

74class FlakyReplay(Flaky): 

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

76 detected during replay. 

77 

78 Carries information allowing the runner to reconstruct the flakiness as 

79 a FlakyFailure exception group for final presentation. 

80 """ 

81 

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

83 super().__init__(reason) 

84 self.reason = reason 

85 self._interesting_origins = interesting_origins 

86 

87 

88class FlakyStrategyDefinition(Flaky): 

89 """ 

90 This function appears to cause inconsistent data generation. 

91 

92 Common causes for this problem are: 

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

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

95 relevant state in from Hypothesis. 

96 

97 .. seealso:: 

98 

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

100 """ 

101 

102 

103class _WrappedBaseException(Exception): 

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

105 

106 

107class FlakyFailure(ExceptionGroup, Flaky): 

108 """ 

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

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

111 did not fail, or caused a distinct error. 

112 

113 Common causes for this problem are: 

114 1. The function 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. 

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

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

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

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

121 don't do that and testing those instead. 

122 

123 .. seealso:: 

124 

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

126 """ 

127 

128 def __new__(cls, msg, group): 

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

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

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

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

133 group = list(group) 

134 for i, exc in enumerate(group): 

135 if not isinstance(exc, Exception): 

136 err = _WrappedBaseException() 

137 err.__cause__ = err.__context__ = exc 

138 group[i] = err 

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

140 

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

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

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

144 def derive(self, excs): 

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

146 

147 

148class FlakyBackendFailure(FlakyFailure): 

149 """ 

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

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

152 

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

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

155 does not reproduce, Hypothesis raises this exception. 

156 """ 

157 

158 

159class InvalidArgument(_Trimmable, TypeError): 

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

161 some manner incorrect.""" 

162 

163 

164class ResolutionFailed(InvalidArgument): 

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

166 

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

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

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

170 """ 

171 

172 

173class InvalidState(HypothesisException): 

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

175 

176 

177class InvalidDefinition(_Trimmable, TypeError): 

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

179 has something wrong with it.""" 

180 

181 

182class HypothesisWarning(HypothesisException, Warning): 

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

184 

185 

186class FailedHealthCheck(_Trimmable): 

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

188 

189 

190class NonInteractiveExampleWarning(HypothesisWarning): 

191 """ 

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

193 

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

195 part of a test suite. 

196 """ 

197 

198 

199class HypothesisDeprecationWarning(HypothesisWarning, FutureWarning): 

200 """A deprecation warning issued by Hypothesis. 

201 

202 Actually inherits from FutureWarning, because DeprecationWarning is 

203 hidden by the default warnings filter. 

204 

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

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

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

208 """ 

209 

210 

211class HypothesisSideeffectWarning(HypothesisWarning): 

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

213 discouraged at import or initialization time because they are 

214 slow or have user-visible side effects. 

215 """ 

216 

217 

218class Frozen(HypothesisException): 

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

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

221 

222 

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

224 if name == "MultipleFailures": 

225 from hypothesis.internal.compat import BaseExceptionGroup 

226 from hypothesis.utils.deprecation import note_deprecation 

227 

228 note_deprecation( 

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

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

231 since="2022-08-02", 

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

233 stacklevel=1, 

234 ) 

235 return BaseExceptionGroup 

236 

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

238 

239 

240class DeadlineExceeded(_Trimmable): 

241 """ 

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

243 setting. 

244 """ 

245 

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

247 super().__init__( 

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

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

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

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

252 ) 

253 self.runtime = runtime 

254 self.deadline = deadline 

255 

256 def __reduce__( 

257 self, 

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

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

260 

261 

262class StopTest(BaseException): 

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

264 the Hypothesis engine, which should then continue normally. 

265 """ 

266 

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

268 super().__init__(repr(testcounter)) 

269 self.testcounter = testcounter 

270 

271 

272class DidNotReproduce(HypothesisException): 

273 pass 

274 

275 

276class Found(HypothesisException): 

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

278 

279 

280class RewindRecursive(Exception): 

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

282 

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

284 self.target = target 

285 

286 

287class SmallSearchSpaceWarning(HypothesisWarning): 

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

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

290 

291 

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

293_valid_cannot_proceed_scopes = CannotProceedScopeT.__args__ # type: ignore 

294 

295 

296class BackendCannotProceed(HypothesisException): 

297 """ 

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

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

300 symbolic execution perhaps in |PrimitiveProvider.realize|. 

301 

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

303 

304 verified: 

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

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

307 Hypothesis will report unsound verification in the backend too. 

308 

309 exhausted: 

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

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

312 native code blocks symbolic reasoning very early. 

313 

314 discard_test_case: 

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

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

317 this backend. 

318 """ 

319 

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

321 if scope not in _valid_cannot_proceed_scopes: 

322 raise InvalidArgument( 

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

324 f"{_valid_cannot_proceed_scopes!r}" 

325 ) 

326 self.scope = scope