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
« 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
5from multidict import CIMultiDict
6from yarl import URL
8from . import hdrs
9from .helpers import CookieMixin
10from .typedefs import LooseHeaders, StrOrURL
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)
74############################################################
75# HTTP Exceptions
76############################################################
79class HTTPException(CookieMixin, Exception):
80 # You should set in subclasses:
81 # status = 200
83 status_code = -1
84 empty_body = False
85 default_reason = "" # Initialized at the end of the module
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
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 )
114 if headers is not None:
115 real_headers = CIMultiDict(headers)
116 else:
117 real_headers = CIMultiDict()
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"
132 self._reason = reason
133 self._text = text
134 self._headers = real_headers
135 self.args = ()
137 def __bool__(self) -> bool:
138 return True
140 @property
141 def status(self) -> int:
142 return self.status_code
144 @property
145 def reason(self) -> str:
146 return self._reason
148 @property
149 def text(self) -> Optional[str]:
150 return self._text
152 @property
153 def headers(self) -> "CIMultiDict[str]":
154 return self._headers
156 def __str__(self) -> str:
157 return self.reason
159 def __repr__(self) -> str:
160 return f"<{self.__class__.__name__}: {self.reason}>"
162 __reduce__ = object.__reduce__
164 def __getnewargs__(self) -> Tuple[Any, ...]:
165 return self.args
168class HTTPError(HTTPException):
169 """Base class for exceptions with status codes in the 400s and 500s."""
172class HTTPRedirection(HTTPException):
173 """Base class for exceptions with status codes in the 300s."""
176class HTTPSuccessful(HTTPException):
177 """Base class for exceptions with status codes in the 200s."""
180class HTTPOk(HTTPSuccessful):
181 status_code = 200
184class HTTPCreated(HTTPSuccessful):
185 status_code = 201
188class HTTPAccepted(HTTPSuccessful):
189 status_code = 202
192class HTTPNonAuthoritativeInformation(HTTPSuccessful):
193 status_code = 203
196class HTTPNoContent(HTTPSuccessful):
197 status_code = 204
198 empty_body = True
201class HTTPResetContent(HTTPSuccessful):
202 status_code = 205
203 empty_body = True
206class HTTPPartialContent(HTTPSuccessful):
207 status_code = 206
210############################################################
211# 3xx redirection
212############################################################
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)
233 @property
234 def location(self) -> URL:
235 return self._location
238class HTTPMultipleChoices(HTTPMove):
239 status_code = 300
242class HTTPMovedPermanently(HTTPMove):
243 status_code = 301
246class HTTPFound(HTTPMove):
247 status_code = 302
250# This one is safe after a POST (the redirected location will be
251# retrieved with GET):
252class HTTPSeeOther(HTTPMove):
253 status_code = 303
256class HTTPNotModified(HTTPRedirection):
257 # FIXME: this should include a date or etag header
258 status_code = 304
259 empty_body = True
262class HTTPUseProxy(HTTPMove):
263 # Not a move, but looks a little like one
264 status_code = 305
267class HTTPTemporaryRedirect(HTTPMove):
268 status_code = 307
271class HTTPPermanentRedirect(HTTPMove):
272 status_code = 308
275############################################################
276# 4xx client error
277############################################################
280class HTTPClientError(HTTPError):
281 pass
284class HTTPBadRequest(HTTPClientError):
285 status_code = 400
288class HTTPUnauthorized(HTTPClientError):
289 status_code = 401
292class HTTPPaymentRequired(HTTPClientError):
293 status_code = 402
296class HTTPForbidden(HTTPClientError):
297 status_code = 403
300class HTTPNotFound(HTTPClientError):
301 status_code = 404
304class HTTPMethodNotAllowed(HTTPClientError):
305 status_code = 405
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
325 @property
326 def allowed_methods(self) -> Set[str]:
327 return self._allowed
329 @property
330 def method(self) -> str:
331 return self._method
334class HTTPNotAcceptable(HTTPClientError):
335 status_code = 406
338class HTTPProxyAuthenticationRequired(HTTPClientError):
339 status_code = 407
342class HTTPRequestTimeout(HTTPClientError):
343 status_code = 408
346class HTTPConflict(HTTPClientError):
347 status_code = 409
350class HTTPGone(HTTPClientError):
351 status_code = 410
354class HTTPLengthRequired(HTTPClientError):
355 status_code = 411
358class HTTPPreconditionFailed(HTTPClientError):
359 status_code = 412
362class HTTPRequestEntityTooLarge(HTTPClientError):
363 status_code = 413
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)
374class HTTPRequestURITooLong(HTTPClientError):
375 status_code = 414
378class HTTPUnsupportedMediaType(HTTPClientError):
379 status_code = 415
382class HTTPRequestRangeNotSatisfiable(HTTPClientError):
383 status_code = 416
386class HTTPExpectationFailed(HTTPClientError):
387 status_code = 417
390class HTTPMisdirectedRequest(HTTPClientError):
391 status_code = 421
394class HTTPUnprocessableEntity(HTTPClientError):
395 status_code = 422
398class HTTPFailedDependency(HTTPClientError):
399 status_code = 424
402class HTTPUpgradeRequired(HTTPClientError):
403 status_code = 426
406class HTTPPreconditionRequired(HTTPClientError):
407 status_code = 428
410class HTTPTooManyRequests(HTTPClientError):
411 status_code = 429
414class HTTPRequestHeaderFieldsTooLarge(HTTPClientError):
415 status_code = 431
418class HTTPUnavailableForLegalReasons(HTTPClientError):
419 status_code = 451
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)
436 @property
437 def link(self) -> URL:
438 return self._link
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.
453class HTTPServerError(HTTPError):
454 pass
457class HTTPInternalServerError(HTTPServerError):
458 status_code = 500
461class HTTPNotImplemented(HTTPServerError):
462 status_code = 501
465class HTTPBadGateway(HTTPServerError):
466 status_code = 502
469class HTTPServiceUnavailable(HTTPServerError):
470 status_code = 503
473class HTTPGatewayTimeout(HTTPServerError):
474 status_code = 504
477class HTTPVersionNotSupported(HTTPServerError):
478 status_code = 505
481class HTTPVariantAlsoNegotiates(HTTPServerError):
482 status_code = 506
485class HTTPInsufficientStorage(HTTPServerError):
486 status_code = 507
489class HTTPNotExtended(HTTPServerError):
490 status_code = 510
493class HTTPNetworkAuthenticationRequired(HTTPServerError):
494 status_code = 511
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
508_initialize_default_reason()
509del _initialize_default_reason