Coverage for /pythoncovmergedfiles/medio/medio/src/aiohttp/aiohttp/web_exceptions.py: 82%
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
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
1import warnings
2from collections.abc import Iterable
3from http import HTTPStatus
4from typing import Any
6from multidict import CIMultiDict
7from yarl import URL
9from . import hdrs
10from .helpers import CookieMixin
11from .typedefs import LooseHeaders, StrOrURL
13__all__ = (
14 "HTTPException",
15 "HTTPError",
16 "HTTPRedirection",
17 "HTTPSuccessful",
18 "HTTPOk",
19 "HTTPCreated",
20 "HTTPAccepted",
21 "HTTPNonAuthoritativeInformation",
22 "HTTPNoContent",
23 "HTTPResetContent",
24 "HTTPPartialContent",
25 "HTTPMove",
26 "HTTPMultipleChoices",
27 "HTTPMovedPermanently",
28 "HTTPFound",
29 "HTTPSeeOther",
30 "HTTPNotModified",
31 "HTTPUseProxy",
32 "HTTPTemporaryRedirect",
33 "HTTPPermanentRedirect",
34 "HTTPClientError",
35 "HTTPBadRequest",
36 "HTTPUnauthorized",
37 "HTTPPaymentRequired",
38 "HTTPForbidden",
39 "HTTPNotFound",
40 "HTTPMethodNotAllowed",
41 "HTTPNotAcceptable",
42 "HTTPProxyAuthenticationRequired",
43 "HTTPRequestTimeout",
44 "HTTPConflict",
45 "HTTPGone",
46 "HTTPLengthRequired",
47 "HTTPPreconditionFailed",
48 "HTTPRequestEntityTooLarge",
49 "HTTPRequestURITooLong",
50 "HTTPUnsupportedMediaType",
51 "HTTPRequestRangeNotSatisfiable",
52 "HTTPExpectationFailed",
53 "HTTPMisdirectedRequest",
54 "HTTPUnprocessableEntity",
55 "HTTPFailedDependency",
56 "HTTPUpgradeRequired",
57 "HTTPPreconditionRequired",
58 "HTTPTooManyRequests",
59 "HTTPRequestHeaderFieldsTooLarge",
60 "HTTPUnavailableForLegalReasons",
61 "HTTPServerError",
62 "HTTPInternalServerError",
63 "HTTPNotImplemented",
64 "HTTPBadGateway",
65 "HTTPServiceUnavailable",
66 "HTTPGatewayTimeout",
67 "HTTPVersionNotSupported",
68 "HTTPVariantAlsoNegotiates",
69 "HTTPInsufficientStorage",
70 "HTTPNotExtended",
71 "HTTPNetworkAuthenticationRequired",
72)
75class NotAppKeyWarning(UserWarning):
76 """Warning when not using AppKey in Application."""
79############################################################
80# HTTP Exceptions
81############################################################
84class HTTPException(CookieMixin, Exception):
85 # You should set in subclasses:
86 # status = 200
88 status_code = -1
89 empty_body = False
90 default_reason = "" # Initialized at the end of the module
92 def __init__(
93 self,
94 *,
95 headers: LooseHeaders | None = None,
96 reason: str | None = None,
97 text: str | None = None,
98 content_type: str | None = None,
99 ) -> None:
100 if reason is None:
101 reason = self.default_reason
102 elif "\r" in reason or "\n" in reason:
103 raise ValueError("Reason cannot contain \\r or \\n")
105 if text is None:
106 if not self.empty_body:
107 text = f"{self.status_code}: {reason}"
108 else:
109 if self.empty_body:
110 warnings.warn(
111 f"text argument is deprecated for HTTP status {self.status_code} "
112 "since 4.0 and scheduled for removal in 5.0 (#3462),"
113 "the response should be provided without a body",
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) -> str | None:
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: LooseHeaders | None = None,
225 reason: str | None = None,
226 text: str | None = None,
227 content_type: str | None = 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: LooseHeaders | None = None,
317 reason: str | None = None,
318 text: str | None = None,
319 content_type: str | None = 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, **kwargs: Any) -> None:
370 kwargs.setdefault("text", f"Maximum request body size {max_size} exceeded.")
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 | None,
424 *,
425 headers: LooseHeaders | None = None,
426 reason: str | None = None,
427 text: str | None = None,
428 content_type: str | None = None,
429 ) -> None:
430 super().__init__(
431 headers=headers, reason=reason, text=text, content_type=content_type
432 )
433 self._link = None
434 if link:
435 self._link = URL(link)
436 self.headers["Link"] = f'<{str(self._link)}>; rel="blocked-by"'
438 @property
439 def link(self) -> URL | None:
440 return self._link
443############################################################
444# 5xx Server Error
445############################################################
446# Response status codes beginning with the digit "5" indicate cases in
447# which the server is aware that it has erred or is incapable of
448# performing the request. Except when responding to a HEAD request, the
449# server SHOULD include an entity containing an explanation of the error
450# situation, and whether it is a temporary or permanent condition. User
451# agents SHOULD display any included entity to the user. These response
452# codes are applicable to any request method.
455class HTTPServerError(HTTPError):
456 pass
459class HTTPInternalServerError(HTTPServerError):
460 status_code = 500
463class HTTPNotImplemented(HTTPServerError):
464 status_code = 501
467class HTTPBadGateway(HTTPServerError):
468 status_code = 502
471class HTTPServiceUnavailable(HTTPServerError):
472 status_code = 503
475class HTTPGatewayTimeout(HTTPServerError):
476 status_code = 504
479class HTTPVersionNotSupported(HTTPServerError):
480 status_code = 505
483class HTTPVariantAlsoNegotiates(HTTPServerError):
484 status_code = 506
487class HTTPInsufficientStorage(HTTPServerError):
488 status_code = 507
491class HTTPNotExtended(HTTPServerError):
492 status_code = 510
495class HTTPNetworkAuthenticationRequired(HTTPServerError):
496 status_code = 511
499def _initialize_default_reason() -> None:
500 for obj in globals().values():
501 if isinstance(obj, type) and issubclass(obj, HTTPException):
502 if obj.status_code >= 0:
503 try:
504 status = HTTPStatus(obj.status_code)
505 obj.default_reason = status.phrase
506 except ValueError:
507 pass
510_initialize_default_reason()
511del _initialize_default_reason