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
« 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
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)
74class NotAppKeyWarning(UserWarning):
75 """Warning when not using AppKey in Application."""
78############################################################
79# HTTP Exceptions
80############################################################
83class HTTPException(CookieMixin, Exception):
84 # You should set in subclasses:
85 # status = 200
87 status_code = -1
88 empty_body = False
89 default_reason = "" # Initialized at the end of the module
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
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 )
118 if headers is not None:
119 real_headers = CIMultiDict(headers)
120 else:
121 real_headers = CIMultiDict()
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"
136 self._reason = reason
137 self._text = text
138 self._headers = real_headers
139 self.args = ()
141 def __bool__(self) -> bool:
142 return True
144 @property
145 def status(self) -> int:
146 return self.status_code
148 @property
149 def reason(self) -> str:
150 return self._reason
152 @property
153 def text(self) -> Optional[str]:
154 return self._text
156 @property
157 def headers(self) -> "CIMultiDict[str]":
158 return self._headers
160 def __str__(self) -> str:
161 return self.reason
163 def __repr__(self) -> str:
164 return f"<{self.__class__.__name__}: {self.reason}>"
166 __reduce__ = object.__reduce__
168 def __getnewargs__(self) -> Tuple[Any, ...]:
169 return self.args
172class HTTPError(HTTPException):
173 """Base class for exceptions with status codes in the 400s and 500s."""
176class HTTPRedirection(HTTPException):
177 """Base class for exceptions with status codes in the 300s."""
180class HTTPSuccessful(HTTPException):
181 """Base class for exceptions with status codes in the 200s."""
184class HTTPOk(HTTPSuccessful):
185 status_code = 200
188class HTTPCreated(HTTPSuccessful):
189 status_code = 201
192class HTTPAccepted(HTTPSuccessful):
193 status_code = 202
196class HTTPNonAuthoritativeInformation(HTTPSuccessful):
197 status_code = 203
200class HTTPNoContent(HTTPSuccessful):
201 status_code = 204
202 empty_body = True
205class HTTPResetContent(HTTPSuccessful):
206 status_code = 205
207 empty_body = True
210class HTTPPartialContent(HTTPSuccessful):
211 status_code = 206
214############################################################
215# 3xx redirection
216############################################################
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)
237 @property
238 def location(self) -> URL:
239 return self._location
242class HTTPMultipleChoices(HTTPMove):
243 status_code = 300
246class HTTPMovedPermanently(HTTPMove):
247 status_code = 301
250class HTTPFound(HTTPMove):
251 status_code = 302
254# This one is safe after a POST (the redirected location will be
255# retrieved with GET):
256class HTTPSeeOther(HTTPMove):
257 status_code = 303
260class HTTPNotModified(HTTPRedirection):
261 # FIXME: this should include a date or etag header
262 status_code = 304
263 empty_body = True
266class HTTPUseProxy(HTTPMove):
267 # Not a move, but looks a little like one
268 status_code = 305
271class HTTPTemporaryRedirect(HTTPMove):
272 status_code = 307
275class HTTPPermanentRedirect(HTTPMove):
276 status_code = 308
279############################################################
280# 4xx client error
281############################################################
284class HTTPClientError(HTTPError):
285 pass
288class HTTPBadRequest(HTTPClientError):
289 status_code = 400
292class HTTPUnauthorized(HTTPClientError):
293 status_code = 401
296class HTTPPaymentRequired(HTTPClientError):
297 status_code = 402
300class HTTPForbidden(HTTPClientError):
301 status_code = 403
304class HTTPNotFound(HTTPClientError):
305 status_code = 404
308class HTTPMethodNotAllowed(HTTPClientError):
309 status_code = 405
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
329 @property
330 def allowed_methods(self) -> Set[str]:
331 return self._allowed
333 @property
334 def method(self) -> str:
335 return self._method
338class HTTPNotAcceptable(HTTPClientError):
339 status_code = 406
342class HTTPProxyAuthenticationRequired(HTTPClientError):
343 status_code = 407
346class HTTPRequestTimeout(HTTPClientError):
347 status_code = 408
350class HTTPConflict(HTTPClientError):
351 status_code = 409
354class HTTPGone(HTTPClientError):
355 status_code = 410
358class HTTPLengthRequired(HTTPClientError):
359 status_code = 411
362class HTTPPreconditionFailed(HTTPClientError):
363 status_code = 412
366class HTTPRequestEntityTooLarge(HTTPClientError):
367 status_code = 413
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)
378class HTTPRequestURITooLong(HTTPClientError):
379 status_code = 414
382class HTTPUnsupportedMediaType(HTTPClientError):
383 status_code = 415
386class HTTPRequestRangeNotSatisfiable(HTTPClientError):
387 status_code = 416
390class HTTPExpectationFailed(HTTPClientError):
391 status_code = 417
394class HTTPMisdirectedRequest(HTTPClientError):
395 status_code = 421
398class HTTPUnprocessableEntity(HTTPClientError):
399 status_code = 422
402class HTTPFailedDependency(HTTPClientError):
403 status_code = 424
406class HTTPUpgradeRequired(HTTPClientError):
407 status_code = 426
410class HTTPPreconditionRequired(HTTPClientError):
411 status_code = 428
414class HTTPTooManyRequests(HTTPClientError):
415 status_code = 429
418class HTTPRequestHeaderFieldsTooLarge(HTTPClientError):
419 status_code = 431
422class HTTPUnavailableForLegalReasons(HTTPClientError):
423 status_code = 451
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"'
442 @property
443 def link(self) -> Optional[URL]:
444 return self._link
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.
459class HTTPServerError(HTTPError):
460 pass
463class HTTPInternalServerError(HTTPServerError):
464 status_code = 500
467class HTTPNotImplemented(HTTPServerError):
468 status_code = 501
471class HTTPBadGateway(HTTPServerError):
472 status_code = 502
475class HTTPServiceUnavailable(HTTPServerError):
476 status_code = 503
479class HTTPGatewayTimeout(HTTPServerError):
480 status_code = 504
483class HTTPVersionNotSupported(HTTPServerError):
484 status_code = 505
487class HTTPVariantAlsoNegotiates(HTTPServerError):
488 status_code = 506
491class HTTPInsufficientStorage(HTTPServerError):
492 status_code = 507
495class HTTPNotExtended(HTTPServerError):
496 status_code = 510
499class HTTPNetworkAuthenticationRequired(HTTPServerError):
500 status_code = 511
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
514_initialize_default_reason()
515del _initialize_default_reason