Allow non-conforming ErrorHandlers (#2259)
* Allow non-conforming ErrorHandlers * Rename to legacy lookup * Updated depnotice * Bump version * Fix formatting * Remove unused import * Fix error messages
This commit is contained in:
parent
50a606adee
commit
5e12edbc38
|
@ -1 +1 @@
|
||||||
__version__ = "21.9.0"
|
__version__ = "21.9.1"
|
||||||
|
|
|
@ -1474,6 +1474,7 @@ class Sanic(BaseSanic, metaclass=TouchUpMeta):
|
||||||
async def _startup(self):
|
async def _startup(self):
|
||||||
self.signalize()
|
self.signalize()
|
||||||
self.finalize()
|
self.finalize()
|
||||||
|
ErrorHandler.finalize(self.error_handler)
|
||||||
TouchUp.run(self)
|
TouchUp.run(self)
|
||||||
|
|
||||||
async def _server_event(
|
async def _server_event(
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from inspect import signature
|
||||||
from typing import Dict, List, Optional, Tuple, Type
|
from typing import Dict, List, Optional, Tuple, Type
|
||||||
|
|
||||||
from sanic.errorpages import BaseRenderer, HTMLRenderer, exception_response
|
from sanic.errorpages import BaseRenderer, HTMLRenderer, exception_response
|
||||||
|
@ -25,7 +26,9 @@ class ErrorHandler:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Beginning in v22.3, the base renderer will be TextRenderer
|
# Beginning in v22.3, the base renderer will be TextRenderer
|
||||||
def __init__(self, fallback: str, base: Type[BaseRenderer] = HTMLRenderer):
|
def __init__(
|
||||||
|
self, fallback: str = "auto", base: Type[BaseRenderer] = HTMLRenderer
|
||||||
|
):
|
||||||
self.handlers: List[Tuple[Type[BaseException], RouteHandler]] = []
|
self.handlers: List[Tuple[Type[BaseException], RouteHandler]] = []
|
||||||
self.cached_handlers: Dict[
|
self.cached_handlers: Dict[
|
||||||
Tuple[Type[BaseException], Optional[str]], Optional[RouteHandler]
|
Tuple[Type[BaseException], Optional[str]], Optional[RouteHandler]
|
||||||
|
@ -34,6 +37,34 @@ class ErrorHandler:
|
||||||
self.fallback = fallback
|
self.fallback = fallback
|
||||||
self.base = base
|
self.base = base
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def finalize(cls, error_handler):
|
||||||
|
if not isinstance(error_handler, cls):
|
||||||
|
error_logger.warning(
|
||||||
|
f"Error handler is non-conforming: {type(error_handler)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
sig = signature(error_handler.lookup)
|
||||||
|
if len(sig.parameters) == 1:
|
||||||
|
error_logger.warning(
|
||||||
|
DeprecationWarning(
|
||||||
|
"You are using a deprecated error handler. The lookup "
|
||||||
|
"method should accept two positional parameters: "
|
||||||
|
"(exception, route_name: Optional[str]). "
|
||||||
|
"Until you upgrade your ErrorHandler.lookup, Blueprint "
|
||||||
|
"specific exceptions will not work properly. Beginning "
|
||||||
|
"in v22.3, the legacy style lookup method will not "
|
||||||
|
"work at all."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
error_handler._lookup = error_handler._legacy_lookup
|
||||||
|
|
||||||
|
def _full_lookup(self, exception, route_name: Optional[str] = None):
|
||||||
|
return self.lookup(exception, route_name)
|
||||||
|
|
||||||
|
def _legacy_lookup(self, exception, route_name: Optional[str] = None):
|
||||||
|
return self.lookup(exception)
|
||||||
|
|
||||||
def add(self, exception, handler, route_names: Optional[List[str]] = None):
|
def add(self, exception, handler, route_names: Optional[List[str]] = None):
|
||||||
"""
|
"""
|
||||||
Add a new exception handler to an already existing handler object.
|
Add a new exception handler to an already existing handler object.
|
||||||
|
@ -56,7 +87,7 @@ class ErrorHandler:
|
||||||
else:
|
else:
|
||||||
self.cached_handlers[(exception, None)] = handler
|
self.cached_handlers[(exception, None)] = handler
|
||||||
|
|
||||||
def lookup(self, exception, route_name: Optional[str]):
|
def lookup(self, exception, route_name: Optional[str] = None):
|
||||||
"""
|
"""
|
||||||
Lookup the existing instance of :class:`ErrorHandler` and fetch the
|
Lookup the existing instance of :class:`ErrorHandler` and fetch the
|
||||||
registered handler for a specific type of exception.
|
registered handler for a specific type of exception.
|
||||||
|
@ -94,6 +125,8 @@ class ErrorHandler:
|
||||||
handler = None
|
handler = None
|
||||||
return handler
|
return handler
|
||||||
|
|
||||||
|
_lookup = _full_lookup
|
||||||
|
|
||||||
def response(self, request, exception):
|
def response(self, request, exception):
|
||||||
"""Fetches and executes an exception handler and returns a response
|
"""Fetches and executes an exception handler and returns a response
|
||||||
object
|
object
|
||||||
|
@ -109,7 +142,7 @@ class ErrorHandler:
|
||||||
or registered handler for that type of exception.
|
or registered handler for that type of exception.
|
||||||
"""
|
"""
|
||||||
route_name = request.name if request else None
|
route_name = request.name if request else None
|
||||||
handler = self.lookup(exception, route_name)
|
handler = self._lookup(exception, route_name)
|
||||||
response = None
|
response = None
|
||||||
try:
|
try:
|
||||||
if handler:
|
if handler:
|
||||||
|
|
|
@ -4,6 +4,7 @@ import warnings
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
|
from websockets.version import version as websockets_version
|
||||||
|
|
||||||
from sanic import Sanic
|
from sanic import Sanic
|
||||||
from sanic.exceptions import (
|
from sanic.exceptions import (
|
||||||
|
@ -16,7 +17,6 @@ from sanic.exceptions import (
|
||||||
abort,
|
abort,
|
||||||
)
|
)
|
||||||
from sanic.response import text
|
from sanic.response import text
|
||||||
from websockets.version import version as websockets_version
|
|
||||||
|
|
||||||
|
|
||||||
class SanicExceptionTestException(Exception):
|
class SanicExceptionTestException(Exception):
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -206,3 +207,23 @@ def test_exception_handler_processed_request_middleware(exception_handler_app):
|
||||||
request, response = exception_handler_app.test_client.get("/8")
|
request, response = exception_handler_app.test_client.get("/8")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == "Done."
|
assert response.text == "Done."
|
||||||
|
|
||||||
|
|
||||||
|
def test_single_arg_exception_handler_notice(exception_handler_app, caplog):
|
||||||
|
class CustomErrorHandler(ErrorHandler):
|
||||||
|
def lookup(self, exception):
|
||||||
|
return super().lookup(exception, None)
|
||||||
|
|
||||||
|
exception_handler_app.error_handler = CustomErrorHandler()
|
||||||
|
|
||||||
|
with caplog.at_level(logging.WARNING):
|
||||||
|
_, response = exception_handler_app.test_client.get("/1")
|
||||||
|
|
||||||
|
assert caplog.records[0].message == (
|
||||||
|
"You are using a deprecated error handler. The lookup method should "
|
||||||
|
"accept two positional parameters: (exception, route_name: "
|
||||||
|
"Optional[str]). Until you upgrade your ErrorHandler.lookup, "
|
||||||
|
"Blueprint specific exceptions will not work properly. Beginning in "
|
||||||
|
"v22.3, the legacy style lookup method will not work at all."
|
||||||
|
)
|
||||||
|
assert response.status == 400
|
||||||
|
|
Loading…
Reference in New Issue
Block a user