From 5c6a0f0c121297362b4c78e4240dd8445b9d9f12 Mon Sep 17 00:00:00 2001 From: pgjones Date: Fri, 16 Apr 2021 12:34:51 +0100 Subject: [PATCH] Fix wrapped view function comparison Wrapped functions are not comparable, see https://bugs.python.org/issue3564, therefore a marker is used to note when the function has been sync wrapped to allow comparison with the wrapped function instead. This ensures that multiple route decorators work without raising exceptions i.e., @app.route("/") @app.route("/a") async def index(): ... works. --- src/flask/app.py | 2 ++ src/flask/helpers.py | 1 + tests/test_async.py | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/flask/app.py b/src/flask/app.py index d6f15e8c..98437cba 100644 --- a/src/flask/app.py +++ b/src/flask/app.py @@ -1048,6 +1048,8 @@ class Flask(Scaffold): self.url_map.add(rule) if view_func is not None: old_func = self.view_functions.get(endpoint) + if getattr(old_func, "_flask_sync_wrapper", False): + old_func = old_func.__wrapped__ if old_func is not None and old_func != view_func: raise AssertionError( "View function mapping is overwriting an existing" diff --git a/src/flask/helpers.py b/src/flask/helpers.py index 1a96e744..6a6bbcf1 100644 --- a/src/flask/helpers.py +++ b/src/flask/helpers.py @@ -780,4 +780,5 @@ def run_async(func): return async_to_sync(inner)(*args, **kwargs) + outer._flask_sync_wrapper = True return outer diff --git a/tests/test_async.py b/tests/test_async.py index 5893ff69..8c096f69 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -24,6 +24,7 @@ def _async_app(): app = Flask(__name__) @app.route("/", methods=["GET", "POST"]) + @app.route("/home", methods=["GET", "POST"]) async def index(): await asyncio.sleep(0) return request.method @@ -57,7 +58,7 @@ def _async_app(): @pytest.mark.skipif(sys.version_info < (3, 7), reason="requires Python >= 3.7") -@pytest.mark.parametrize("path", ["/", "/bp/"]) +@pytest.mark.parametrize("path", ["/", "/home", "/bp/"]) def test_async_route(path, async_app): test_client = async_app.test_client() response = test_client.get(path)