from __future__ import annotations from typing import Any, Callable from sanic.base.meta import SanicMeta from sanic.models.futures import FutureException class ExceptionMixin(metaclass=SanicMeta): def __init__(self, *args, **kwargs) -> None: self._future_exceptions: set[FutureException] = set() def _apply_exception_handler(self, handler: FutureException): raise NotImplementedError # noqa def exception( self, *exceptions: type[Exception] | list[type[Exception]], apply: bool = True, ) -> Callable: """Decorator used to register an exception handler for the current application or blueprint instance. This method allows you to define a handler for specific exceptions that may be raised within the routes of this blueprint. You can specify one or more exception types to catch, and the handler will be applied to those exceptions. When used on a Blueprint, the handler will only be applied to routes registered under that blueprint. That means they only apply to requests that have been matched, and the exception is raised within the handler function (or middleware) for that route. A general exception like `NotFound` should only be registered on the application instance, not on a blueprint. See [Exceptions](/en/guide/best-practices/exceptions.html) for more information. Args: exceptions (Union[Type[Exception], List[Type[Exception]]]): List of Python exceptions to be caught by the handler. apply (bool, optional): Whether the exception handler should be applied. Defaults to True. Returns: Callable: A decorated method to handle global exceptions for any route registered under this blueprint. Example: ```python from sanic import Blueprint, text bp = Blueprint('my_blueprint') @bp.exception(Exception) def handle_exception(request, exception): return text("Oops, something went wrong!", status=500) ``` ```python from sanic import Sanic, NotFound, text app = Sanic('MyApp') @app.exception(NotFound) def ignore_404s(request, exception): return text(f"Yep, I totally found the page: {request.url}") """ # noqa: E501 def decorator(handler): nonlocal apply nonlocal exceptions if isinstance(exceptions[0], list): exceptions = tuple(*exceptions) future_exception = FutureException(handler, exceptions) self._future_exceptions.add(future_exception) if apply: self._apply_exception_handler(future_exception) return handler return decorator def all_exceptions( self, handler: Callable[..., Any] ) -> Callable[..., Any]: """Enables the process of creating a global exception handler as a convenience. This following two examples are equivalent: ```python @app.exception(Exception) async def handler(request: Request, exception: Exception) -> HTTPResponse: return text(f"Exception raised: {exception}") ``` ```python @app.all_exceptions async def handler(request: Request, exception: Exception) -> HTTPResponse: return text(f"Exception raised: {exception}") ``` Args: handler (Callable[..., Any]): A coroutine function to handle exceptions. Returns: Callable[..., Any]: A decorated method to handle global exceptions for any route registered under this blueprint. """ # noqa: E501 return self.exception(Exception)(handler)