test and documentation

This commit is contained in:
Dale Kube 2026-03-01 19:22:43 -06:00
parent f4e700c1f3
commit 1fc69bd3f4
4 changed files with 48 additions and 0 deletions

View file

@ -3,6 +3,8 @@ Version 3.2.0
Unreleased
- Optimize request dispatching by caching the result of ``ensure_sync`` for view
functions in ``_sync_view_functions``, reducing CPU overhead. :issue:`9999`
- Drop support for Python 3.9. :pr:`5730`
- Remove previously deprecated code: ``__version__``. :pr:`5648`
- ``RequestContext`` has merged with ``AppContext``. ``RequestContext`` is now

View file

@ -107,6 +107,10 @@ the decorated function,
return wrapper
To improve performance, consider caching the result of ``ensure_sync`` if your
extension calls it frequently on the same function. This is how Flask internally
optimizes request dispatching.
Check the changelog of the extension you want to use to see if they've
implemented async support, or make a feature request or PR to them.

View file

@ -971,6 +971,10 @@ class Flask(App):
be a response object. In order to convert the return value to a
proper response object, call :func:`make_response`.
.. versionchanged:: 3.2
The result of ``ensure_sync`` is cached in ``_sync_view_functions``
to improve performance.
.. versionchanged:: 0.7
This no longer does the exception handling, this code was
moved to the new :meth:`full_dispatch_request`.
@ -1077,6 +1081,10 @@ class Flask(App):
Override this method to change how the app runs async views.
.. versionchanged:: 3.2
The result of this method is cached during request dispatching
to improve performance.
.. versionadded:: 2.0
"""
if iscoroutinefunction(func):

View file

@ -1968,3 +1968,37 @@ def test_app_freed_on_zero_refcount():
assert weak() is None
finally:
gc.enable()
def test_sync_view_functions_cache(app, client):
"""Test that the _sync_view_functions cache is populated and used."""
@app.route("/test")
def test_view():
return "Hello"
import unittest.mock
with unittest.mock.patch.object(app, 'ensure_sync', wraps=app.ensure_sync) as mock_ensure_sync:
# First request should call ensure_sync
response = client.get("/test")
assert response.status_code == 200
assert mock_ensure_sync.call_count == 1
# Second request should hit the cache and not call ensure_sync
response = client.get("/test")
assert response.status_code == 200
assert mock_ensure_sync.call_count == 1
# Direct mutation test (to verify the cache is bound to endpoint)
def new_view():
return "World"
# Simulating a user directly updating the view functions after setup
# Because it's already cached, this mutation won't affect _sync_view_functions
app.view_functions["test"] = new_view
# Ensure that it still returns the old result due to the cache
response = client.get("/test")
assert response.status_code == 200
assert response.data == b"Hello"