From 44973125c15304b4262c51c78b5a86bd1daafa86 Mon Sep 17 00:00:00 2001 From: Ashley Sommer Date: Thu, 14 May 2020 09:54:47 +1000 Subject: [PATCH] Reverse named_response_middlware execution order, to match normal response middleware execution order. Fixes #1847 Adds a test to ensure fix is correct Adds an example which demonstrates correct blueprint-middlware execution order behavior. --- .../blueprint_middlware_execution_order.py | 43 +++++++++++++++++++ sanic/app.py | 2 +- tests/test_blueprints.py | 34 ++++++++++++++- 3 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 examples/blueprint_middlware_execution_order.py diff --git a/examples/blueprint_middlware_execution_order.py b/examples/blueprint_middlware_execution_order.py new file mode 100644 index 00000000..38fc4cb1 --- /dev/null +++ b/examples/blueprint_middlware_execution_order.py @@ -0,0 +1,43 @@ +from sanic import Sanic, Blueprint +from sanic.response import text +''' +Demonstrates that blueprint request middleware are executed in the order they +are added. And blueprint response middleware are executed in _reverse_ order. +On a valid request, it should print "1 2 3 6 5 4" to terminal +''' + +app = Sanic(__name__) + +bp = Blueprint("bp_"+__name__) + +@bp.middleware('request') +def request_middleware_1(request): + print('1') + +@bp.middleware('request') +def request_middleware_2(request): + print('2') + +@bp.middleware('request') +def request_middleware_3(request): + print('3') + +@bp.middleware('response') +def resp_middleware_4(request, response): + print('4') + +@bp.middleware('response') +def resp_middleware_5(request, response): + print('5') + +@bp.middleware('response') +def resp_middleware_6(request, response): + print('6') + +@bp.route('/') +def pop_handler(request): + return text('hello world') + +app.blueprint(bp, url_prefix='/bp') + +app.run(host="0.0.0.0", port=8000, debug=True, auto_reload=False) diff --git a/sanic/app.py b/sanic/app.py index 6d7f2daf..7ef1c942 100644 --- a/sanic/app.py +++ b/sanic/app.py @@ -653,7 +653,7 @@ class Sanic: if _rn not in self.named_response_middleware: self.named_response_middleware[_rn] = deque() if middleware not in self.named_response_middleware[_rn]: - self.named_response_middleware[_rn].append(middleware) + self.named_response_middleware[_rn].appendleft(middleware) # Decorator def middleware(self, middleware_or_request): diff --git a/tests/test_blueprints.py b/tests/test_blueprints.py index 47b2b907..69a2118a 100644 --- a/tests/test_blueprints.py +++ b/tests/test_blueprints.py @@ -253,7 +253,7 @@ def test_several_bp_with_host(app): def test_bp_middleware(app): - blueprint = Blueprint("test_middleware") + blueprint = Blueprint("test_bp_middleware") @blueprint.middleware("response") async def process_response(request, response): @@ -270,6 +270,38 @@ def test_bp_middleware(app): assert response.status == 200 assert response.text == "FAIL" +def test_bp_middleware_order(app): + blueprint = Blueprint("test_bp_middleware_order") + order = list() + @blueprint.middleware("request") + def mw_1(request): + order.append(1) + @blueprint.middleware("request") + def mw_2(request): + order.append(2) + @blueprint.middleware("request") + def mw_3(request): + order.append(3) + @blueprint.middleware("response") + def mw_4(request, response): + order.append(6) + @blueprint.middleware("response") + def mw_5(request, response): + order.append(5) + @blueprint.middleware("response") + def mw_6(request, response): + order.append(4) + + @blueprint.route("/") + def process_response(request): + return text("OK") + + app.blueprint(blueprint) + order.clear() + request, response = app.test_client.get("/") + + assert response.status == 200 + assert order == [1, 2, 3, 4, 5, 6] def test_bp_exception_handler(app): blueprint = Blueprint("test_middleware")