Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
exceptions.py882 linesDownload Raw Back to werkzeug
1"""Implements a number of Python exceptions which can be raised from within2a view to trigger a standard HTTP non-200 response.3 4Usage Example5-------------6 7.. code-block:: python8 9    from werkzeug.wrappers.request import Request10    from werkzeug.exceptions import HTTPException, NotFound11 12    def view(request):13        raise NotFound()14 15    @Request.application16    def application(request):17        try:18            return view(request)19        except HTTPException as e:20            return e21 22As you can see from this example those exceptions are callable WSGI23applications. However, they are not Werkzeug response objects. You24can get a response object by calling ``get_response()`` on a HTTP25exception.26 27Keep in mind that you may have to pass an environ (WSGI) or scope28(ASGI) to ``get_response()`` because some errors fetch additional29information relating to the request.30 31If you want to hook in a different exception page to say, a 404 status32code, you can add a second except for a specific subclass of an error:33 34.. code-block:: python35 36    @Request.application37    def application(request):38        try:39            return view(request)40        except NotFound as e:41            return not_found(request)42        except HTTPException as e:43            return e44 45"""46 47from __future__ import annotations48 49import typing as t50from datetime import datetime51 52from markupsafe import escape53from markupsafe import Markup54 55from ._internal import _get_environ56 57if t.TYPE_CHECKING:58    from _typeshed.wsgi import StartResponse59    from _typeshed.wsgi import WSGIEnvironment60 61    from .datastructures import WWWAuthenticate62    from .sansio.response import Response63    from .wrappers.request import Request as WSGIRequest64    from .wrappers.response import Response as WSGIResponse65 66 67class HTTPException(Exception):68    """The base class for all HTTP exceptions. This exception can be called as a WSGI69    application to render a default error page or you can catch the subclasses70    of it independently and render nicer error messages.71 72    .. versionchanged:: 2.173        Removed the ``wrap`` class method.74    """75 76    code: int | None = None77    description: str | None = None78 79    def __init__(80        self,81        description: str | None = None,82        response: Response | None = None,83    ) -> None:84        super().__init__()85        if description is not None:86            self.description = description87        self.response = response88 89    @property90    def name(self) -> str:91        """The status name."""92        from .http import HTTP_STATUS_CODES93 94        return HTTP_STATUS_CODES.get(self.code, "Unknown Error")  # type: ignore95 96    def get_description(97        self,98        environ: WSGIEnvironment | None = None,99        scope: dict[str, t.Any] | None = None,100    ) -> str:101        """Get the description."""102        if self.description is None:103            description = ""104        else:105            description = self.description106 107        description = escape(description).replace("\n", Markup("<br>"))108        return f"<p>{description}</p>"109 110    def get_body(111        self,112        environ: WSGIEnvironment | None = None,113        scope: dict[str, t.Any] | None = None,114    ) -> str:115        """Get the HTML body."""116        return (117            "<!doctype html>\n"118            "<html lang=en>\n"119            f"<title>{self.code} {escape(self.name)}</title>\n"120            f"<h1>{escape(self.name)}</h1>\n"121            f"{self.get_description(environ)}\n"122        )123 124    def get_headers(125        self,126        environ: WSGIEnvironment | None = None,127        scope: dict[str, t.Any] | None = None,128    ) -> list[tuple[str, str]]:129        """Get a list of headers."""130        return [("Content-Type", "text/html; charset=utf-8")]131 132    def get_response(133        self,134        environ: WSGIEnvironment | WSGIRequest | None = None,135        scope: dict[str, t.Any] | None = None,136    ) -> Response:137        """Get a response object.  If one was passed to the exception138        it's returned directly.139 140        :param environ: the optional environ for the request.  This141                        can be used to modify the response depending142                        on how the request looked like.143        :return: a :class:`Response` object or a subclass thereof.144        """145        from .wrappers.response import Response as WSGIResponse  # noqa: F811146 147        if self.response is not None:148            return self.response149        if environ is not None:150            environ = _get_environ(environ)151        headers = self.get_headers(environ, scope)152        return WSGIResponse(self.get_body(environ, scope), self.code, headers)153 154    def __call__(155        self, environ: WSGIEnvironment, start_response: StartResponse156    ) -> t.Iterable[bytes]:157        """Call the exception as WSGI application.158 159        :param environ: the WSGI environment.160        :param start_response: the response callable provided by the WSGI161                               server.162        """163        response = t.cast("WSGIResponse", self.get_response(environ))164        return response(environ, start_response)165 166    def __str__(self) -> str:167        code = self.code if self.code is not None else "???"168        return f"{code} {self.name}: {self.description}"169 170    def __repr__(self) -> str:171        code = self.code if self.code is not None else "???"172        return f"<{type(self).__name__} '{code}: {self.name}'>"173 174 175class BadRequest(HTTPException):176    """*400* `Bad Request`177 178    Raise if the browser sends something to the application the application179    or server cannot handle.180    """181 182    code = 400183    description = (184        "The browser (or proxy) sent a request that this server could "185        "not understand."186    )187 188 189class BadRequestKeyError(BadRequest, KeyError):190    """An exception that is used to signal both a :exc:`KeyError` and a191    :exc:`BadRequest`. Used by many of the datastructures.192    """193 194    _description = BadRequest.description195    #: Show the KeyError along with the HTTP error message in the196    #: response. This should be disabled in production, but can be197    #: useful in a debug mode.198    show_exception = False199 200    def __init__(self, arg: str | None = None, *args: t.Any, **kwargs: t.Any):201        super().__init__(*args, **kwargs)202 203        if arg is None:204            KeyError.__init__(self)205        else:206            KeyError.__init__(self, arg)207 208    @property  # type: ignore209    def description(self) -> str:210        if self.show_exception:211            return (212                f"{self._description}\n"213                f"{KeyError.__name__}: {KeyError.__str__(self)}"214            )215 216        return self._description217 218    @description.setter219    def description(self, value: str) -> None:220        self._description = value221 222 223class ClientDisconnected(BadRequest):224    """Internal exception that is raised if Werkzeug detects a disconnected225    client.  Since the client is already gone at that point attempting to226    send the error message to the client might not work and might ultimately227    result in another exception in the server.  Mainly this is here so that228    it is silenced by default as far as Werkzeug is concerned.229 230    Since disconnections cannot be reliably detected and are unspecified231    by WSGI to a large extent this might or might not be raised if a client232    is gone.233 234    .. versionadded:: 0.8235    """236 237 238class SecurityError(BadRequest):239    """Raised if something triggers a security error.  This is otherwise240    exactly like a bad request error.241 242    .. versionadded:: 0.9243    """244 245 246class BadHost(BadRequest):247    """Raised if the submitted host is badly formatted.248 249    .. versionadded:: 0.11.2250    """251 252 253class Unauthorized(HTTPException):254    """*401* ``Unauthorized``255 256    Raise if the user is not authorized to access a resource.257 258    The ``www_authenticate`` argument should be used to set the259    ``WWW-Authenticate`` header. This is used for HTTP basic auth and260    other schemes. Use :class:`~werkzeug.datastructures.WWWAuthenticate`261    to create correctly formatted values. Strictly speaking a 401262    response is invalid if it doesn't provide at least one value for263    this header, although real clients typically don't care.264 265    :param description: Override the default message used for the body266        of the response.267    :param www-authenticate: A single value, or list of values, for the268        WWW-Authenticate header(s).269 270    .. versionchanged:: 2.0271        Serialize multiple ``www_authenticate`` items into multiple272        ``WWW-Authenticate`` headers, rather than joining them273        into a single value, for better interoperability.274 275    .. versionchanged:: 0.15.3276        If the ``www_authenticate`` argument is not set, the277        ``WWW-Authenticate`` header is not set.278 279    .. versionchanged:: 0.15.3280        The ``response`` argument was restored.281 282    .. versionchanged:: 0.15.1283        ``description`` was moved back as the first argument, restoring284         its previous position.285 286    .. versionchanged:: 0.15.0287        ``www_authenticate`` was added as the first argument, ahead of288        ``description``.289    """290 291    code = 401292    description = (293        "The server could not verify that you are authorized to access"294        " the URL requested. You either supplied the wrong credentials"295        " (e.g. a bad password), or your browser doesn't understand"296        " how to supply the credentials required."297    )298 299    def __init__(300        self,301        description: str | None = None,302        response: Response | None = None,303        www_authenticate: None | (WWWAuthenticate | t.Iterable[WWWAuthenticate]) = None,304    ) -> None:305        super().__init__(description, response)306 307        from .datastructures import WWWAuthenticate308 309        if isinstance(www_authenticate, WWWAuthenticate):310            www_authenticate = (www_authenticate,)311 312        self.www_authenticate = www_authenticate313 314    def get_headers(315        self,316        environ: WSGIEnvironment | None = None,317        scope: dict[str, t.Any] | None = None,318    ) -> list[tuple[str, str]]:319        headers = super().get_headers(environ, scope)320        if self.www_authenticate:321            headers.extend(("WWW-Authenticate", str(x)) for x in self.www_authenticate)322        return headers323 324 325class Forbidden(HTTPException):326    """*403* `Forbidden`327 328    Raise if the user doesn't have the permission for the requested resource329    but was authenticated.330    """331 332    code = 403333    description = (334        "You don't have the permission to access the requested"335        " resource. It is either read-protected or not readable by the"336        " server."337    )338 339 340class NotFound(HTTPException):341    """*404* `Not Found`342 343    Raise if a resource does not exist and never existed.344    """345 346    code = 404347    description = (348        "The requested URL was not found on the server. If you entered"349        " the URL manually please check your spelling and try again."350    )351 352 353class MethodNotAllowed(HTTPException):354    """*405* `Method Not Allowed`355 356    Raise if the server used a method the resource does not handle.  For357    example `POST` if the resource is view only.  Especially useful for REST.358 359    The first argument for this exception should be a list of allowed methods.360    Strictly speaking the response would be invalid if you don't provide valid361    methods in the header which you can do with that list.362    """363 364    code = 405365    description = "The method is not allowed for the requested URL."366 367    def __init__(368        self,369        valid_methods: t.Iterable[str] | None = None,370        description: str | None = None,371        response: Response | None = None,372    ) -> None:373        """Takes an optional list of valid http methods374        starting with werkzeug 0.3 the list will be mandatory."""375        super().__init__(description=description, response=response)376        self.valid_methods = valid_methods377 378    def get_headers(379        self,380        environ: WSGIEnvironment | None = None,381        scope: dict[str, t.Any] | None = None,382    ) -> list[tuple[str, str]]:383        headers = super().get_headers(environ, scope)384        if self.valid_methods:385            headers.append(("Allow", ", ".join(self.valid_methods)))386        return headers387 388 389class NotAcceptable(HTTPException):390    """*406* `Not Acceptable`391 392    Raise if the server can't return any content conforming to the393    `Accept` headers of the client.394    """395 396    code = 406397    description = (398        "The resource identified by the request is only capable of"399        " generating response entities which have content"400        " characteristics not acceptable according to the accept"401        " headers sent in the request."402    )403 404 405class RequestTimeout(HTTPException):406    """*408* `Request Timeout`407 408    Raise to signalize a timeout.409    """410 411    code = 408412    description = (413        "The server closed the network connection because the browser"414        " didn't finish the request within the specified time."415    )416 417 418class Conflict(HTTPException):419    """*409* `Conflict`420 421    Raise to signal that a request cannot be completed because it conflicts422    with the current state on the server.423 424    .. versionadded:: 0.7425    """426 427    code = 409428    description = (429        "A conflict happened while processing the request. The"430        " resource might have been modified while the request was being"431        " processed."432    )433 434 435class Gone(HTTPException):436    """*410* `Gone`437 438    Raise if a resource existed previously and went away without new location.439    """440 441    code = 410442    description = (443        "The requested URL is no longer available on this server and"444        " there is no forwarding address. If you followed a link from a"445        " foreign page, please contact the author of this page."446    )447 448 449class LengthRequired(HTTPException):450    """*411* `Length Required`451 452    Raise if the browser submitted data but no ``Content-Length`` header which453    is required for the kind of processing the server does.454    """455 456    code = 411457    description = (458        "A request with this method requires a valid <code>Content-"459        "Length</code> header."460    )461 462 463class PreconditionFailed(HTTPException):464    """*412* `Precondition Failed`465 466    Status code used in combination with ``If-Match``, ``If-None-Match``, or467    ``If-Unmodified-Since``.468    """469 470    code = 412471    description = (472        "The precondition on the request for the URL failed positive evaluation."473    )474 475 476class RequestEntityTooLarge(HTTPException):477    """*413* `Request Entity Too Large`478 479    The status code one should return if the data submitted exceeded a given480    limit.481    """482 483    code = 413484    description = "The data value transmitted exceeds the capacity limit."485 486 487class RequestURITooLarge(HTTPException):488    """*414* `Request URI Too Large`489 490    Like *413* but for too long URLs.491    """492 493    code = 414494    description = (495        "The length of the requested URL exceeds the capacity limit for"496        " this server. The request cannot be processed."497    )498 499 500class UnsupportedMediaType(HTTPException):501    """*415* `Unsupported Media Type`502 503    The status code returned if the server is unable to handle the media type504    the client transmitted.505    """506 507    code = 415508    description = (509        "The server does not support the media type transmitted in the request."510    )511 512 513class RequestedRangeNotSatisfiable(HTTPException):514    """*416* `Requested Range Not Satisfiable`515 516    The client asked for an invalid part of the file.517 518    .. versionadded:: 0.7519    """520 521    code = 416522    description = "The server cannot provide the requested range."523 524    def __init__(525        self,526        length: int | None = None,527        units: str = "bytes",528        description: str | None = None,529        response: Response | None = None,530    ) -> None:531        """Takes an optional `Content-Range` header value based on ``length``532        parameter.533        """534        super().__init__(description=description, response=response)535        self.length = length536        self.units = units537 538    def get_headers(539        self,540        environ: WSGIEnvironment | None = None,541        scope: dict[str, t.Any] | None = None,542    ) -> list[tuple[str, str]]:543        headers = super().get_headers(environ, scope)544        if self.length is not None:545            headers.append(("Content-Range", f"{self.units} */{self.length}"))546        return headers547 548 549class ExpectationFailed(HTTPException):550    """*417* `Expectation Failed`551 552    The server cannot meet the requirements of the Expect request-header.553 554    .. versionadded:: 0.7555    """556 557    code = 417558    description = "The server could not meet the requirements of the Expect header"559 560 561class ImATeapot(HTTPException):562    """*418* `I'm a teapot`563 564    The server should return this if it is a teapot and someone attempted565    to brew coffee with it.566 567    .. versionadded:: 0.7568    """569 570    code = 418571    description = "This server is a teapot, not a coffee machine"572 573 574class UnprocessableEntity(HTTPException):575    """*422* `Unprocessable Entity`576 577    Used if the request is well formed, but the instructions are otherwise578    incorrect.579    """580 581    code = 422582    description = (583        "The request was well-formed but was unable to be followed due"584        " to semantic errors."585    )586 587 588class Locked(HTTPException):589    """*423* `Locked`590 591    Used if the resource that is being accessed is locked.592    """593 594    code = 423595    description = "The resource that is being accessed is locked."596 597 598class FailedDependency(HTTPException):599    """*424* `Failed Dependency`600 601    Used if the method could not be performed on the resource602    because the requested action depended on another action and that action failed.603    """604 605    code = 424606    description = (607        "The method could not be performed on the resource because the"608        " requested action depended on another action and that action"609        " failed."610    )611 612 613class PreconditionRequired(HTTPException):614    """*428* `Precondition Required`615 616    The server requires this request to be conditional, typically to prevent617    the lost update problem, which is a race condition between two or more618    clients attempting to update a resource through PUT or DELETE. By requiring619    each client to include a conditional header ("If-Match" or "If-Unmodified-620    Since") with the proper value retained from a recent GET request, the621    server ensures that each client has at least seen the previous revision of622    the resource.623    """624 625    code = 428626    description = (627        "This request is required to be conditional; try using"628        ' "If-Match" or "If-Unmodified-Since".'629    )630 631 632class _RetryAfter(HTTPException):633    """Adds an optional ``retry_after`` parameter which will set the634    ``Retry-After`` header. May be an :class:`int` number of seconds or635    a :class:`~datetime.datetime`.636    """637 638    def __init__(639        self,640        description: str | None = None,641        response: Response | None = None,642        retry_after: datetime | int | None = None,643    ) -> None:644        super().__init__(description, response)645        self.retry_after = retry_after646 647    def get_headers(648        self,649        environ: WSGIEnvironment | None = None,650        scope: dict[str, t.Any] | None = None,651    ) -> list[tuple[str, str]]:652        headers = super().get_headers(environ, scope)653 654        if self.retry_after:655            if isinstance(self.retry_after, datetime):656                from .http import http_date657 658                value = http_date(self.retry_after)659            else:660                value = str(self.retry_after)661 662            headers.append(("Retry-After", value))663 664        return headers665 666 667class TooManyRequests(_RetryAfter):668    """*429* `Too Many Requests`669 670    The server is limiting the rate at which this user receives671    responses, and this request exceeds that rate. (The server may use672    any convenient method to identify users and their request rates).673    The server may include a "Retry-After" header to indicate how long674    the user should wait before retrying.675 676    :param retry_after: If given, set the ``Retry-After`` header to this677        value. May be an :class:`int` number of seconds or a678        :class:`~datetime.datetime`.679 680    .. versionchanged:: 1.0681        Added ``retry_after`` parameter.682    """683 684    code = 429685    description = "This user has exceeded an allotted request count. Try again later."686 687 688class RequestHeaderFieldsTooLarge(HTTPException):689    """*431* `Request Header Fields Too Large`690 691    The server refuses to process the request because the header fields are too692    large. One or more individual fields may be too large, or the set of all693    headers is too large.694    """695 696    code = 431697    description = "One or more header fields exceeds the maximum size."698 699 700class UnavailableForLegalReasons(HTTPException):701    """*451* `Unavailable For Legal Reasons`702 703    This status code indicates that the server is denying access to the704    resource as a consequence of a legal demand.705    """706 707    code = 451708    description = "Unavailable for legal reasons."709 710 711class InternalServerError(HTTPException):712    """*500* `Internal Server Error`713 714    Raise if an internal server error occurred.  This is a good fallback if an715    unknown error occurred in the dispatcher.716 717    .. versionchanged:: 1.0.0718        Added the :attr:`original_exception` attribute.719    """720 721    code = 500722    description = (723        "The server encountered an internal error and was unable to"724        " complete your request. Either the server is overloaded or"725        " there is an error in the application."726    )727 728    def __init__(729        self,730        description: str | None = None,731        response: Response | None = None,732        original_exception: BaseException | None = None,733    ) -> None:734        #: The original exception that caused this 500 error. Can be735        #: used by frameworks to provide context when handling736        #: unexpected errors.737        self.original_exception = original_exception738        super().__init__(description=description, response=response)739 740 741class NotImplemented(HTTPException):742    """*501* `Not Implemented`743 744    Raise if the application does not support the action requested by the745    browser.746    """747 748    code = 501749    description = "The server does not support the action requested by the browser."750 751 752class BadGateway(HTTPException):753    """*502* `Bad Gateway`754 755    If you do proxying in your application you should return this status code756    if you received an invalid response from the upstream server it accessed757    in attempting to fulfill the request.758    """759 760    code = 502761    description = (762        "The proxy server received an invalid response from an upstream server."763    )764 765 766class ServiceUnavailable(_RetryAfter):767    """*503* `Service Unavailable`768 769    Status code you should return if a service is temporarily770    unavailable.771 772    :param retry_after: If given, set the ``Retry-After`` header to this773        value. May be an :class:`int` number of seconds or a774        :class:`~datetime.datetime`.775 776    .. versionchanged:: 1.0777        Added ``retry_after`` parameter.778    """779 780    code = 503781    description = (782        "The server is temporarily unable to service your request due"783        " to maintenance downtime or capacity problems. Please try"784        " again later."785    )786 787 788class GatewayTimeout(HTTPException):789    """*504* `Gateway Timeout`790 791    Status code you should return if a connection to an upstream server792    times out.793    """794 795    code = 504796    description = "The connection to an upstream server timed out."797 798 799class HTTPVersionNotSupported(HTTPException):800    """*505* `HTTP Version Not Supported`801 802    The server does not support the HTTP protocol version used in the request.803    """804 805    code = 505806    description = (807        "The server does not support the HTTP protocol version used in the request."808    )809 810 811default_exceptions: dict[int, type[HTTPException]] = {}812 813 814def _find_exceptions() -> None:815    for obj in globals().values():816        try:817            is_http_exception = issubclass(obj, HTTPException)818        except TypeError:819            is_http_exception = False820        if not is_http_exception or obj.code is None:821            continue822        old_obj = default_exceptions.get(obj.code, None)823        if old_obj is not None and issubclass(obj, old_obj):824            continue825        default_exceptions[obj.code] = obj826 827 828_find_exceptions()829del _find_exceptions830 831 832class Aborter:833    """When passed a dict of code -> exception items it can be used as834    callable that raises exceptions.  If the first argument to the835    callable is an integer it will be looked up in the mapping, if it's836    a WSGI application it will be raised in a proxy exception.837 838    The rest of the arguments are forwarded to the exception constructor.839    """840 841    def __init__(842        self,843        mapping: dict[int, type[HTTPException]] | None = None,844        extra: dict[int, type[HTTPException]] | None = None,845    ) -> None:846        if mapping is None:847            mapping = default_exceptions848        self.mapping = dict(mapping)849        if extra is not None:850            self.mapping.update(extra)851 852    def __call__(853        self, code: int | Response, *args: t.Any, **kwargs: t.Any854    ) -> t.NoReturn:855        from .sansio.response import Response856 857        if isinstance(code, Response):858            raise HTTPException(response=code)859 860        if code not in self.mapping:861            raise LookupError(f"no exception for {code!r}")862 863        raise self.mapping[code](*args, **kwargs)864 865 866def abort(status: int | Response, *args: t.Any, **kwargs: t.Any) -> t.NoReturn:867    """Raises an :py:exc:`HTTPException` for the given status code or WSGI868    application.869 870    If a status code is given, it will be looked up in the list of871    exceptions and will raise that exception.  If passed a WSGI application,872    it will wrap it in a proxy WSGI exception and raise that::873 874       abort(404)  # 404 Not Found875       abort(Response('Hello World'))876 877    """878    _aborter(status, *args, **kwargs)879 880 881_aborter: Aborter = Aborter()882 
codekingpro/portable-devtools · Team Ai