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

211 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:52 +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 

74############################################################ 

75# HTTP Exceptions 

76############################################################ 

77 

78 

79class HTTPException(CookieMixin, Exception): 

80 # You should set in subclasses: 

81 # status = 200 

82 

83 status_code = -1 

84 empty_body = False 

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

86 

87 def __init__( 

88 self, 

89 *, 

90 headers: Optional[LooseHeaders] = None, 

91 reason: Optional[str] = None, 

92 text: Optional[str] = None, 

93 content_type: Optional[str] = None, 

94 ) -> None: 

95 super().__init__() 

96 if reason is None: 

97 reason = self.default_reason 

98 

99 if text is None: 

100 if not self.empty_body: 

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

102 else: 

103 if self.empty_body: 

104 warnings.warn( 

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

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

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

108 self.status_code 

109 ), 

110 DeprecationWarning, 

111 stacklevel=2, 

112 ) 

113 

114 if headers is not None: 

115 real_headers = CIMultiDict(headers) 

116 else: 

117 real_headers = CIMultiDict() 

118 

119 if content_type is not None: 

120 if not text: 

121 warnings.warn( 

122 "content_type without text is deprecated " 

123 "since 4.0 and scheduled for removal in 5.0 " 

124 "(#3462)", 

125 DeprecationWarning, 

126 stacklevel=2, 

127 ) 

128 real_headers[hdrs.CONTENT_TYPE] = content_type 

129 elif hdrs.CONTENT_TYPE not in real_headers and text: 

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

131 

132 self._reason = reason 

133 self._text = text 

134 self._headers = real_headers 

135 self.args = () 

136 

137 def __bool__(self) -> bool: 

138 return True 

139 

140 @property 

141 def status(self) -> int: 

142 return self.status_code 

143 

144 @property 

145 def reason(self) -> str: 

146 return self._reason 

147 

148 @property 

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

150 return self._text 

151 

152 @property 

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

154 return self._headers 

155 

156 def __str__(self) -> str: 

157 return self.reason 

158 

159 def __repr__(self) -> str: 

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

161 

162 __reduce__ = object.__reduce__ 

163 

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

165 return self.args 

166 

167 

168class HTTPError(HTTPException): 

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

170 

171 

172class HTTPRedirection(HTTPException): 

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

174 

175 

176class HTTPSuccessful(HTTPException): 

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

178 

179 

180class HTTPOk(HTTPSuccessful): 

181 status_code = 200 

182 

183 

184class HTTPCreated(HTTPSuccessful): 

185 status_code = 201 

186 

187 

188class HTTPAccepted(HTTPSuccessful): 

189 status_code = 202 

190 

191 

192class HTTPNonAuthoritativeInformation(HTTPSuccessful): 

193 status_code = 203 

194 

195 

196class HTTPNoContent(HTTPSuccessful): 

197 status_code = 204 

198 empty_body = True 

199 

200 

201class HTTPResetContent(HTTPSuccessful): 

202 status_code = 205 

203 empty_body = True 

204 

205 

206class HTTPPartialContent(HTTPSuccessful): 

207 status_code = 206 

208 

209 

210############################################################ 

211# 3xx redirection 

212############################################################ 

213 

214 

215class HTTPMove(HTTPRedirection): 

216 def __init__( 

217 self, 

218 location: StrOrURL, 

219 *, 

220 headers: Optional[LooseHeaders] = None, 

221 reason: Optional[str] = None, 

222 text: Optional[str] = None, 

223 content_type: Optional[str] = None, 

224 ) -> None: 

225 if not location: 

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

227 super().__init__( 

228 headers=headers, reason=reason, text=text, content_type=content_type 

229 ) 

230 self._location = URL(location) 

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

232 

233 @property 

234 def location(self) -> URL: 

235 return self._location 

236 

237 

238class HTTPMultipleChoices(HTTPMove): 

239 status_code = 300 

240 

241 

242class HTTPMovedPermanently(HTTPMove): 

243 status_code = 301 

244 

245 

246class HTTPFound(HTTPMove): 

247 status_code = 302 

248 

249 

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

251# retrieved with GET): 

252class HTTPSeeOther(HTTPMove): 

253 status_code = 303 

254 

255 

256class HTTPNotModified(HTTPRedirection): 

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

258 status_code = 304 

259 empty_body = True 

260 

261 

262class HTTPUseProxy(HTTPMove): 

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

264 status_code = 305 

265 

266 

267class HTTPTemporaryRedirect(HTTPMove): 

268 status_code = 307 

269 

270 

271class HTTPPermanentRedirect(HTTPMove): 

272 status_code = 308 

273 

274 

275############################################################ 

276# 4xx client error 

277############################################################ 

278 

279 

280class HTTPClientError(HTTPError): 

281 pass 

282 

283 

284class HTTPBadRequest(HTTPClientError): 

285 status_code = 400 

286 

287 

288class HTTPUnauthorized(HTTPClientError): 

289 status_code = 401 

290 

291 

292class HTTPPaymentRequired(HTTPClientError): 

293 status_code = 402 

294 

295 

296class HTTPForbidden(HTTPClientError): 

297 status_code = 403 

298 

299 

300class HTTPNotFound(HTTPClientError): 

301 status_code = 404 

302 

303 

304class HTTPMethodNotAllowed(HTTPClientError): 

305 status_code = 405 

306 

307 def __init__( 

308 self, 

309 method: str, 

310 allowed_methods: Iterable[str], 

311 *, 

312 headers: Optional[LooseHeaders] = None, 

313 reason: Optional[str] = None, 

314 text: Optional[str] = None, 

315 content_type: Optional[str] = None, 

316 ) -> None: 

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

318 super().__init__( 

319 headers=headers, reason=reason, text=text, content_type=content_type 

320 ) 

321 self.headers["Allow"] = allow 

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

323 self._method = method 

324 

325 @property 

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

327 return self._allowed 

328 

329 @property 

330 def method(self) -> str: 

331 return self._method 

332 

333 

334class HTTPNotAcceptable(HTTPClientError): 

335 status_code = 406 

336 

337 

338class HTTPProxyAuthenticationRequired(HTTPClientError): 

339 status_code = 407 

340 

341 

342class HTTPRequestTimeout(HTTPClientError): 

343 status_code = 408 

344 

345 

346class HTTPConflict(HTTPClientError): 

347 status_code = 409 

348 

349 

350class HTTPGone(HTTPClientError): 

351 status_code = 410 

352 

353 

354class HTTPLengthRequired(HTTPClientError): 

355 status_code = 411 

356 

357 

358class HTTPPreconditionFailed(HTTPClientError): 

359 status_code = 412 

360 

361 

362class HTTPRequestEntityTooLarge(HTTPClientError): 

363 status_code = 413 

364 

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

366 kwargs.setdefault( 

367 "text", 

368 "Maximum request body size {} exceeded, " 

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

370 ) 

371 super().__init__(**kwargs) 

372 

373 

374class HTTPRequestURITooLong(HTTPClientError): 

375 status_code = 414 

376 

377 

378class HTTPUnsupportedMediaType(HTTPClientError): 

379 status_code = 415 

380 

381 

382class HTTPRequestRangeNotSatisfiable(HTTPClientError): 

383 status_code = 416 

384 

385 

386class HTTPExpectationFailed(HTTPClientError): 

387 status_code = 417 

388 

389 

390class HTTPMisdirectedRequest(HTTPClientError): 

391 status_code = 421 

392 

393 

394class HTTPUnprocessableEntity(HTTPClientError): 

395 status_code = 422 

396 

397 

398class HTTPFailedDependency(HTTPClientError): 

399 status_code = 424 

400 

401 

402class HTTPUpgradeRequired(HTTPClientError): 

403 status_code = 426 

404 

405 

406class HTTPPreconditionRequired(HTTPClientError): 

407 status_code = 428 

408 

409 

410class HTTPTooManyRequests(HTTPClientError): 

411 status_code = 429 

412 

413 

414class HTTPRequestHeaderFieldsTooLarge(HTTPClientError): 

415 status_code = 431 

416 

417 

418class HTTPUnavailableForLegalReasons(HTTPClientError): 

419 status_code = 451 

420 

421 def __init__( 

422 self, 

423 link: StrOrURL, 

424 *, 

425 headers: Optional[LooseHeaders] = None, 

426 reason: Optional[str] = None, 

427 text: Optional[str] = None, 

428 content_type: Optional[str] = None, 

429 ) -> None: 

430 super().__init__( 

431 headers=headers, reason=reason, text=text, content_type=content_type 

432 ) 

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

434 self._link = URL(link) 

435 

436 @property 

437 def link(self) -> URL: 

438 return self._link 

439 

440 

441############################################################ 

442# 5xx Server Error 

443############################################################ 

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

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

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

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

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

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

450# codes are applicable to any request method. 

451 

452 

453class HTTPServerError(HTTPError): 

454 pass 

455 

456 

457class HTTPInternalServerError(HTTPServerError): 

458 status_code = 500 

459 

460 

461class HTTPNotImplemented(HTTPServerError): 

462 status_code = 501 

463 

464 

465class HTTPBadGateway(HTTPServerError): 

466 status_code = 502 

467 

468 

469class HTTPServiceUnavailable(HTTPServerError): 

470 status_code = 503 

471 

472 

473class HTTPGatewayTimeout(HTTPServerError): 

474 status_code = 504 

475 

476 

477class HTTPVersionNotSupported(HTTPServerError): 

478 status_code = 505 

479 

480 

481class HTTPVariantAlsoNegotiates(HTTPServerError): 

482 status_code = 506 

483 

484 

485class HTTPInsufficientStorage(HTTPServerError): 

486 status_code = 507 

487 

488 

489class HTTPNotExtended(HTTPServerError): 

490 status_code = 510 

491 

492 

493class HTTPNetworkAuthenticationRequired(HTTPServerError): 

494 status_code = 511 

495 

496 

497def _initialize_default_reason() -> None: 

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

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

500 if obj.status_code >= 0: 

501 try: 

502 status = HTTPStatus(obj.status_code) 

503 obj.default_reason = status.phrase 

504 except ValueError: 

505 pass 

506 

507 

508_initialize_default_reason() 

509del _initialize_default_reason