Merge branch 'main' into zhiwei/bp-copy
This commit is contained in:
commit
54cee45d06
@ -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:
|
||||||
|
@ -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")
|
||||||
|
@ -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:
|
||||||
"""
|
"""
|
||||||
|
@ -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")
|
||||||
|
@ -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):
|
||||||
|
@ -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]
|
||||||
|
)
|
||||||
|
@ -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):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user