Coverage for /pythoncovmergedfiles/medio/medio/src/aiohttp/aiohttp/web_exceptions.py: 83%

214 statements  

« prev     ^ index     » next       coverage.py v7.4.0, created at 2024-01-26 06:16 +0000

1import warnings 

2from http import HTTPStatus 

3from typing import Any, Iterable, Optional, Set, Tuple 

4 

5from multidict import CIMultiDict 

6from yarl import URL 

7 

8from . import hdrs 

9from .helpers import CookieMixin 

10from .typedefs import LooseHeaders, StrOrURL 

11 

12__all__ = ( 

13 "HTTPException", 

14 "HTTPError", 

15 "HTTPRedirection", 

16 "HTTPSuccessful", 

17 "HTTPOk", 

18 "HTTPCreated", 

19 "HTTPAccepted", 

20 "HTTPNonAuthoritativeInformation", 

21 "HTTPNoContent", 

22 "HTTPResetContent", 

23 "HTTPPartialContent", 

24 "HTTPMove", 

25 "HTTPMultipleChoices", 

26 "HTTPMovedPermanently", 

27 "HTTPFound", 

28 "HTTPSeeOther", 

29 "HTTPNotModified", 

30 "HTTPUseProxy", 

31 "HTTPTemporaryRedirect", 

32 "HTTPPermanentRedirect", 

33 "HTTPClientError", 

34 "HTTPBadRequest", 

35 "HTTPUnauthorized", 

36 "HTTPPaymentRequired", 

37 "HTTPForbidden", 

38 "HTTPNotFound", 

39 "HTTPMethodNotAllowed", 

40 "HTTPNotAcceptable", 

41 "HTTPProxyAuthenticationRequired", 

42 "HTTPRequestTimeout", 

43 "HTTPConflict", 

44 "HTTPGone", 

45 "HTTPLengthRequired", 

46 "HTTPPreconditionFailed", 

47 "HTTPRequestEntityTooLarge", 

48 "HTTPRequestURITooLong", 

49 "HTTPUnsupportedMediaType", 

50 "HTTPRequestRangeNotSatisfiable", 

51 "HTTPExpectationFailed", 

52 "HTTPMisdirectedRequest", 

53 "HTTPUnprocessableEntity", 

54 "HTTPFailedDependency", 

55 "HTTPUpgradeRequired", 

56 "HTTPPreconditionRequired", 

57 "HTTPTooManyRequests", 

58 "HTTPRequestHeaderFieldsTooLarge", 

59 "HTTPUnavailableForLegalReasons", 

60 "HTTPServerError", 

61 "HTTPInternalServerError", 

62 "HTTPNotImplemented", 

63 "HTTPBadGateway", 

64 "HTTPServiceUnavailable", 

65 "HTTPGatewayTimeout", 

66 "HTTPVersionNotSupported", 

67 "HTTPVariantAlsoNegotiates", 

68 "HTTPInsufficientStorage", 

69 "HTTPNotExtended", 

70 "HTTPNetworkAuthenticationRequired", 

71) 

72 

73 

74class NotAppKeyWarning(UserWarning): 

75 """Warning when not using AppKey in Application.""" 

76 

77 

78############################################################ 

79# HTTP Exceptions 

80############################################################ 

81 

82 

83class HTTPException(CookieMixin, Exception): 

84 # You should set in subclasses: 

85 # status = 200 

86 

87 status_code = -1 

88 empty_body = False 

89 default_reason = "" # Initialized at the end of the module 

90 

91 def __init__( 

92 self, 

93 *, 

94 headers: Optional[LooseHeaders] = None, 

95 reason: Optional[str] = None, 

96 text: Optional[str] = None, 

97 content_type: Optional[str] = None, 

98 ) -> None: 

99 super().__init__() 

100 if reason is None: 

101 reason = self.default_reason 

102 

103 if text is None: 

104 if not self.empty_body: 

105 text = f"{self.status_code}: {reason}" 

106 else: 

107 if self.empty_body: 

108 warnings.warn( 

109 "text argument is deprecated for HTTP status {} " 

110 "since 4.0 and scheduled for removal in 5.0 (#3462)," 

111 "the response should be provided without a body".format( 

112 self.status_code 

113 ), 

114 DeprecationWarning, 

115 stacklevel=2, 

116 ) 

117 

118 if headers is not None: 

119 real_headers = CIMultiDict(headers) 

120 else: 

121 real_headers = CIMultiDict() 

122 

123 if content_type is not None: 

124 if not text: 

125 warnings.warn( 

126 "content_type without text is deprecated " 

127 "since 4.0 and scheduled for removal in 5.0 " 

128 "(#3462)", 

129 DeprecationWarning, 

130 stacklevel=2, 

131 ) 

132 real_headers[hdrs.CONTENT_TYPE] = content_type 

133 elif hdrs.CONTENT_TYPE not in real_headers and text: 

134 real_headers[hdrs.CONTENT_TYPE] = "text/plain" 

135 

136 self._reason = reason 

137 self._text = text 

138 self._headers = real_headers 

139 self.args = () 

140 

141 def __bool__(self) -> bool: 

142 return True 

143 

144 @property 

145 def status(self) -> int: 

146 return self.status_code 

147 

148 @property 

149 def reason(self) -> str: 

150 return self._reason 

151 

152 @property 

153 def text(self) -> Optional[str]: 

154 return self._text 

155 

156 @property 

157 def headers(self) -> "CIMultiDict[str]": 

158 return self._headers 

159 

160 def __str__(self) -> str: 

161 return self.reason 

162 

163 def __repr__(self) -> str: 

164 return f"<{self.__class__.__name__}: {self.reason}>" 

165 

166 __reduce__ = object.__reduce__ 

167 

168 def __getnewargs__(self) -> Tuple[Any, ...]: 

169 return self.args 

170 

171 

172class HTTPError(HTTPException): 

173 """Base class for exceptions with status codes in the 400s and 500s.""" 

174 

175 

176class HTTPRedirection(HTTPException): 

177 """Base class for exceptions with status codes in the 300s.""" 

178 

179 

180class HTTPSuccessful(HTTPException): 

181 """Base class for exceptions with status codes in the 200s.""" 

182 

183 

184class HTTPOk(HTTPSuccessful): 

185 status_code = 200 

186 

187 

188class HTTPCreated(HTTPSuccessful): 

189 status_code = 201 

190 

191 

192class HTTPAccepted(HTTPSuccessful): 

193 status_code = 202 

194 

195 

196class HTTPNonAuthoritativeInformation(HTTPSuccessful): 

197 status_code = 203 

198 

199 

200class HTTPNoContent(HTTPSuccessful): 

201 status_code = 204 

202 empty_body = True 

203 

204 

205class HTTPResetContent(HTTPSuccessful): 

206 status_code = 205 

207 empty_body = True 

208 

209 

210class HTTPPartialContent(HTTPSuccessful): 

211 status_code = 206 

212 

213 

214############################################################ 

215# 3xx redirection 

216############################################################ 

217 

218 

219class HTTPMove(HTTPRedirection): 

220 def __init__( 

221 self, 

222 location: StrOrURL, 

223 *, 

224 headers: Optional[LooseHeaders] = None, 

225 reason: Optional[str] = None, 

226 text: Optional[str] = None, 

227 content_type: Optional[str] = None, 

228 ) -> None: 

229 if not location: 

230 raise ValueError("HTTP redirects need a location to redirect to.") 

231 super().__init__( 

232 headers=headers, reason=reason, text=text, content_type=content_type 

233 ) 

234 self._location = URL(location) 

235 self.headers["Location"] = str(self.location) 

236 

237 @property 

238 def location(self) -> URL: 

239 return self._location 

240 

241 

242class HTTPMultipleChoices(HTTPMove): 

243 status_code = 300 

244 

245 

246class HTTPMovedPermanently(HTTPMove): 

247 status_code = 301 

248 

249 

250class HTTPFound(HTTPMove): 

251 status_code = 302 

252 

253 

254# This one is safe after a POST (the redirected location will be 

255# retrieved with GET): 

256class HTTPSeeOther(HTTPMove): 

257 status_code = 303 

258 

259 

260class HTTPNotModified(HTTPRedirection): 

261 # FIXME: this should include a date or etag header 

262 status_code = 304 

263 empty_body = True 

264 

265 

266class HTTPUseProxy(HTTPMove): 

267 # Not a move, but looks a little like one 

268 status_code = 305 

269 

270 

271class HTTPTemporaryRedirect(HTTPMove): 

272 status_code = 307 

273 

274 

275class HTTPPermanentRedirect(HTTPMove): 

276 status_code = 308 

277 

278 

279############################################################ 

280# 4xx client error 

281############################################################ 

282 

283 

284class HTTPClientError(HTTPError): 

285 pass 

286 

287 

288class HTTPBadRequest(HTTPClientError): 

289 status_code = 400 

290 

291 

292class HTTPUnauthorized(HTTPClientError): 

293 status_code = 401 

294 

295 

296class HTTPPaymentRequired(HTTPClientError): 

297 status_code = 402 

298 

299 

300class HTTPForbidden(HTTPClientError): 

301 status_code = 403 

302 

303 

304class HTTPNotFound(HTTPClientError): 

305 status_code = 404 

306 

307 

308class HTTPMethodNotAllowed(HTTPClientError): 

309 status_code = 405 

310 

311 def __init__( 

312 self, 

313 method: str, 

314 allowed_methods: Iterable[str], 

315 *, 

316 headers: Optional[LooseHeaders] = None, 

317 reason: Optional[str] = None, 

318 text: Optional[str] = None, 

319 content_type: Optional[str] = None, 

320 ) -> None: 

321 allow = ",".join(sorted(allowed_methods)) 

322 super().__init__( 

323 headers=headers, reason=reason, text=text, content_type=content_type 

324 ) 

325 self.headers["Allow"] = allow 

326 self._allowed: Set[str] = set(allowed_methods) 

327 self._method = method 

328 

329 @property 

330 def allowed_methods(self) -> Set[str]: 

331 return self._allowed 

332 

333 @property 

334 def method(self) -> str: 

335 return self._method 

336 

337 

338class HTTPNotAcceptable(HTTPClientError): 

339 status_code = 406 

340 

341 

342class HTTPProxyAuthenticationRequired(HTTPClientError): 

343 status_code = 407 

344 

345 

346class HTTPRequestTimeout(HTTPClientError): 

347 status_code = 408 

348 

349 

350class HTTPConflict(HTTPClientError): 

351 status_code = 409 

352 

353 

354class HTTPGone(HTTPClientError): 

355 status_code = 410 

356 

357 

358class HTTPLengthRequired(HTTPClientError): 

359 status_code = 411 

360 

361 

362class HTTPPreconditionFailed(HTTPClientError): 

363 status_code = 412 

364 

365 

366class HTTPRequestEntityTooLarge(HTTPClientError): 

367 status_code = 413 

368 

369 def __init__(self, max_size: int, actual_size: int, **kwargs: Any) -> None: 

370 kwargs.setdefault( 

371 "text", 

372 "Maximum request body size {} exceeded, " 

373 "actual body size {}".format(max_size, actual_size), 

374 ) 

375 super().__init__(**kwargs) 

376 

377 

378class HTTPRequestURITooLong(HTTPClientError): 

379 status_code = 414 

380 

381 

382class HTTPUnsupportedMediaType(HTTPClientError): 

383 status_code = 415 

384 

385 

386class HTTPRequestRangeNotSatisfiable(HTTPClientError): 

387 status_code = 416 

388 

389 

390class HTTPExpectationFailed(HTTPClientError): 

391 status_code = 417 

392 

393 

394class HTTPMisdirectedRequest(HTTPClientError): 

395 status_code = 421 

396 

397 

398class HTTPUnprocessableEntity(HTTPClientError): 

399 status_code = 422 

400 

401 

402class HTTPFailedDependency(HTTPClientError): 

403 status_code = 424 

404 

405 

406class HTTPUpgradeRequired(HTTPClientError): 

407 status_code = 426 

408 

409 

410class HTTPPreconditionRequired(HTTPClientError): 

411 status_code = 428 

412 

413 

414class HTTPTooManyRequests(HTTPClientError): 

415 status_code = 429 

416 

417 

418class HTTPRequestHeaderFieldsTooLarge(HTTPClientError): 

419 status_code = 431 

420 

421 

422class HTTPUnavailableForLegalReasons(HTTPClientError): 

423 status_code = 451 

424 

425 def __init__( 

426 self, 

427 link: Optional[StrOrURL], 

428 *, 

429 headers: Optional[LooseHeaders] = None, 

430 reason: Optional[str] = None, 

431 text: Optional[str] = None, 

432 content_type: Optional[str] = None, 

433 ) -> None: 

434 super().__init__( 

435 headers=headers, reason=reason, text=text, content_type=content_type 

436 ) 

437 self._link = None 

438 if link: 

439 self._link = URL(link) 

440 self.headers["Link"] = f'<{str(self._link)}>; rel="blocked-by"' 

441 

442 @property 

443 def link(self) -> Optional[URL]: 

444 return self._link 

445 

446 

447############################################################ 

448# 5xx Server Error 

449############################################################ 

450# Response status codes beginning with the digit "5" indicate cases in 

451# which the server is aware that it has erred or is incapable of 

452# performing the request. Except when responding to a HEAD request, the 

453# server SHOULD include an entity containing an explanation of the error 

454# situation, and whether it is a temporary or permanent condition. User 

455# agents SHOULD display any included entity to the user. These response 

456# codes are applicable to any request method. 

457 

458 

459class HTTPServerError(HTTPError): 

460 pass 

461 

462 

463class HTTPInternalServerError(HTTPServerError): 

464 status_code = 500 

465 

466 

467class HTTPNotImplemented(HTTPServerError): 

468 status_code = 501 

469 

470 

471class HTTPBadGateway(HTTPServerError): 

472 status_code = 502 

473 

474 

475class HTTPServiceUnavailable(HTTPServerError): 

476 status_code = 503 

477 

478 

479class HTTPGatewayTimeout(HTTPServerError): 

480 status_code = 504 

481 

482 

483class HTTPVersionNotSupported(HTTPServerError): 

484 status_code = 505 

485 

486 

487class HTTPVariantAlsoNegotiates(HTTPServerError): 

488 status_code = 506 

489 

490 

491class HTTPInsufficientStorage(HTTPServerError): 

492 status_code = 507 

493 

494 

495class HTTPNotExtended(HTTPServerError): 

496 status_code = 510 

497 

498 

499class HTTPNetworkAuthenticationRequired(HTTPServerError): 

500 status_code = 511 

501 

502 

503def _initialize_default_reason() -> None: 

504 for obj in globals().values(): 

505 if isinstance(obj, type) and issubclass(obj, HTTPException): 

506 if obj.status_code >= 0: 

507 try: 

508 status = HTTPStatus(obj.status_code) 

509 obj.default_reason = status.phrase 

510 except ValueError: 

511 pass 

512 

513 

514_initialize_default_reason() 

515del _initialize_default_reason