Merge branch 'main' into zhiwei/bp-copy

This commit is contained in:
Zhiwei 2021-08-07 15:29:37 -05:00 committed by GitHub
commit 54cee45d06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 76 additions and 16 deletions

View File

@ -893,6 +893,8 @@ class Sanic(BaseSanic, metaclass=TouchUpMeta):
self.websocket_tasks.add(fut) self.websocket_tasks.add(fut)
try: try:
await fut await fut
except Exception as e:
self.error_handler.log(request, e)
except (CancelledError, ConnectionClosed): except (CancelledError, ConnectionClosed):
pass pass
finally: finally:

View File

@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
from collections.abc import MutableSequence from collections.abc import MutableSequence
from functools import partial
from typing import TYPE_CHECKING, List, Optional, Union from typing import TYPE_CHECKING, List, Optional, Union
@ -229,3 +230,15 @@ class BlueprintGroup(MutableSequence):
args = list(args)[1:] args = list(args)[1:]
return register_middleware_for_blueprints(fn) return register_middleware_for_blueprints(fn)
return register_middleware_for_blueprints return register_middleware_for_blueprints
def on_request(self, middleware=None):
if callable(middleware):
return self.middleware(middleware, "request")
else:
return partial(self.middleware, attach_to="request")
def on_response(self, middleware=None):
if callable(middleware):
return self.middleware(middleware, "response")
else:
return partial(self.middleware, attach_to="response")

View File

@ -1,5 +1,3 @@
from traceback import format_exc
from sanic.errorpages import exception_response from sanic.errorpages import exception_response
from sanic.exceptions import ( from sanic.exceptions import (
ContentRangeError, ContentRangeError,
@ -99,7 +97,6 @@ class ErrorHandler:
if response is None: if response is None:
response = self.default(request, exception) response = self.default(request, exception)
except Exception: except Exception:
self.log(format_exc())
try: try:
url = repr(request.url) url = repr(request.url)
except AttributeError: except AttributeError:
@ -115,11 +112,6 @@ class ErrorHandler:
return text("An error occurred while handling an error", 500) return text("An error occurred while handling an error", 500)
return response return response
def log(self, message, level="error"):
"""
Deprecated, do not use.
"""
def default(self, request, exception): def default(self, request, exception):
""" """
Provide a default behavior for the objects of :class:`ErrorHandler`. Provide a default behavior for the objects of :class:`ErrorHandler`.
@ -135,6 +127,11 @@ class ErrorHandler:
:class:`Exception` :class:`Exception`
:return: :return:
""" """
self.log(request, exception)
return exception_response(request, exception, self.debug)
@staticmethod
def log(request, exception):
quiet = getattr(exception, "quiet", False) quiet = getattr(exception, "quiet", False)
if quiet is False: if quiet is False:
try: try:
@ -142,13 +139,10 @@ class ErrorHandler:
except AttributeError: except AttributeError:
url = "unknown" url = "unknown"
self.log(format_exc())
error_logger.exception( error_logger.exception(
"Exception occurred while handling uri: %s", url "Exception occurred while handling uri: %s", url
) )
return exception_response(request, exception, self.debug)
class ContentRangeHandler: class ContentRangeHandler:
""" """

View File

@ -360,6 +360,7 @@ async def test_request_handle_exception(app):
_, response = await app.asgi_client.get("/error-prone") _, response = await app.asgi_client.get("/error-prone")
assert response.status_code == 503 assert response.status_code == 503
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_request_exception_suppressed_by_middleware(app): async def test_request_exception_suppressed_by_middleware(app):
@app.get("/error-prone") @app.get("/error-prone")

View File

@ -116,6 +116,16 @@ def test_bp_group(app: Sanic):
global MIDDLEWARE_INVOKE_COUNTER global MIDDLEWARE_INVOKE_COUNTER
MIDDLEWARE_INVOKE_COUNTER["request"] += 1 MIDDLEWARE_INVOKE_COUNTER["request"] += 1
@blueprint_group_1.on_request
def blueprint_group_1_convenience_1(request):
global MIDDLEWARE_INVOKE_COUNTER
MIDDLEWARE_INVOKE_COUNTER["request"] += 1
@blueprint_group_1.on_request()
def blueprint_group_1_convenience_2(request):
global MIDDLEWARE_INVOKE_COUNTER
MIDDLEWARE_INVOKE_COUNTER["request"] += 1
@blueprint_3.route("/") @blueprint_3.route("/")
def blueprint_3_default_route(request): def blueprint_3_default_route(request):
return text("BP3_OK") return text("BP3_OK")
@ -129,6 +139,16 @@ def test_bp_group(app: Sanic):
global MIDDLEWARE_INVOKE_COUNTER global MIDDLEWARE_INVOKE_COUNTER
MIDDLEWARE_INVOKE_COUNTER["response"] += 1 MIDDLEWARE_INVOKE_COUNTER["response"] += 1
@blueprint_group_2.on_response
def blueprint_group_2_middleware_convenience_1(request, response):
global MIDDLEWARE_INVOKE_COUNTER
MIDDLEWARE_INVOKE_COUNTER["response"] += 1
@blueprint_group_2.on_response()
def blueprint_group_2_middleware_convenience_2(request, response):
global MIDDLEWARE_INVOKE_COUNTER
MIDDLEWARE_INVOKE_COUNTER["response"] += 1
app.blueprint(blueprint_group_2) app.blueprint(blueprint_group_2)
@app.route("/") @app.route("/")
@ -147,8 +167,8 @@ def test_bp_group(app: Sanic):
_, response = app.test_client.get("/api/bp3") _, response = app.test_client.get("/api/bp3")
assert response.text == "BP3_OK" assert response.text == "BP3_OK"
assert MIDDLEWARE_INVOKE_COUNTER["response"] == 3 assert MIDDLEWARE_INVOKE_COUNTER["response"] == 9
assert MIDDLEWARE_INVOKE_COUNTER["request"] == 4 assert MIDDLEWARE_INVOKE_COUNTER["request"] == 8
def test_bp_group_list_operations(app: Sanic): def test_bp_group_list_operations(app: Sanic):

View File

@ -1,3 +1,4 @@
import logging
import warnings import warnings
import pytest import pytest
@ -232,3 +233,20 @@ def test_sanic_exception(exception_app):
request, response = exception_app.test_client.get("/old_abort") request, response = exception_app.test_client.get("/old_abort")
assert response.status == 500 assert response.status == 500
assert len(w) == 1 and "deprecated" in w[0].message.args[0] assert len(w) == 1 and "deprecated" in w[0].message.args[0]
def test_exception_in_ws_logged(caplog):
app = Sanic(__file__)
@app.websocket("/feed")
async def feed(request, ws):
raise Exception("...")
with caplog.at_level(logging.INFO):
app.test_client.websocket("/feed")
assert caplog.record_tuples[1][0] == "sanic.error"
assert caplog.record_tuples[1][1] == logging.ERROR
assert (
"Exception occurred while handling uri:" in caplog.record_tuples[1][2]
)

View File

@ -37,14 +37,19 @@ def test_middleware_request_as_convenience(app):
async def handler1(request): async def handler1(request):
results.append(request) results.append(request)
@app.route("/") @app.on_request()
async def handler2(request): async def handler2(request):
results.append(request)
@app.route("/")
async def handler3(request):
return text("OK") return text("OK")
request, response = app.test_client.get("/") request, response = app.test_client.get("/")
assert response.text == "OK" assert response.text == "OK"
assert type(results[0]) is Request assert type(results[0]) is Request
assert type(results[1]) is Request
def test_middleware_response(app): def test_middleware_response(app):
@ -79,7 +84,12 @@ def test_middleware_response_as_convenience(app):
results.append(request) results.append(request)
@app.on_response @app.on_response
async def process_response(request, response): async def process_response_1(request, response):
results.append(request)
results.append(response)
@app.on_response()
async def process_response_2(request, response):
results.append(request) results.append(request)
results.append(response) results.append(response)
@ -93,6 +103,8 @@ def test_middleware_response_as_convenience(app):
assert type(results[0]) is Request assert type(results[0]) is Request
assert type(results[1]) is Request assert type(results[1]) is Request
assert isinstance(results[2], HTTPResponse) assert isinstance(results[2], HTTPResponse)
assert type(results[3]) is Request
assert isinstance(results[4], HTTPResponse)
def test_middleware_response_as_convenience_called(app): def test_middleware_response_as_convenience_called(app):