107 lines
3.8 KiB
Python
107 lines
3.8 KiB
Python
from typing import Any, Callable, List, Set, Type, Union
|
|
|
|
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: Union[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)
|