Add async support
This allows for async functions to be passed to the Flask class
instance, for example as a view function,
@app.route("/")
async def index():
return "Async hello"
this comes with a cost though of poorer performance than using the
sync equivalent.
asgiref is the standard way to run async code within a sync context,
and is used in Django making it a safe and sane choice for this.
This commit is contained in:
parent
8fa1fdfc96
commit
c9f774d650
11 changed files with 165 additions and 9 deletions
|
|
@ -4,6 +4,7 @@ import pkgutil
|
|||
import sys
|
||||
from collections import defaultdict
|
||||
from functools import update_wrapper
|
||||
from inspect import iscoroutinefunction
|
||||
|
||||
from jinja2 import FileSystemLoader
|
||||
from werkzeug.exceptions import default_exceptions
|
||||
|
|
@ -12,6 +13,7 @@ from werkzeug.exceptions import HTTPException
|
|||
from .cli import AppGroup
|
||||
from .globals import current_app
|
||||
from .helpers import locked_cached_property
|
||||
from .helpers import run_async
|
||||
from .helpers import send_from_directory
|
||||
from .templating import _default_template_ctx_processor
|
||||
|
||||
|
|
@ -484,7 +486,7 @@ class Scaffold:
|
|||
"""
|
||||
|
||||
def decorator(f):
|
||||
self.view_functions[endpoint] = f
|
||||
self.view_functions[endpoint] = self.ensure_sync(f)
|
||||
return f
|
||||
|
||||
return decorator
|
||||
|
|
@ -508,7 +510,7 @@ class Scaffold:
|
|||
return value from the view, and further request handling is
|
||||
stopped.
|
||||
"""
|
||||
self.before_request_funcs[None].append(f)
|
||||
self.before_request_funcs.setdefault(None, []).append(self.ensure_sync(f))
|
||||
return f
|
||||
|
||||
@setupmethod
|
||||
|
|
@ -524,7 +526,7 @@ class Scaffold:
|
|||
should not be used for actions that must execute, such as to
|
||||
close resources. Use :meth:`teardown_request` for that.
|
||||
"""
|
||||
self.after_request_funcs[None].append(f)
|
||||
self.after_request_funcs.setdefault(None, []).append(self.ensure_sync(f))
|
||||
return f
|
||||
|
||||
@setupmethod
|
||||
|
|
@ -563,7 +565,7 @@ class Scaffold:
|
|||
debugger can still access it. This behavior can be controlled
|
||||
by the ``PRESERVE_CONTEXT_ON_EXCEPTION`` configuration variable.
|
||||
"""
|
||||
self.teardown_request_funcs[None].append(f)
|
||||
self.teardown_request_funcs.setdefault(None, []).append(self.ensure_sync(f))
|
||||
return f
|
||||
|
||||
@setupmethod
|
||||
|
|
@ -659,7 +661,7 @@ class Scaffold:
|
|||
" instead."
|
||||
)
|
||||
|
||||
self.error_handler_spec[None][code][exc_class] = f
|
||||
self.error_handler_spec[None][code][exc_class] = self.ensure_sync(f)
|
||||
|
||||
@staticmethod
|
||||
def _get_exc_class_and_code(exc_class_or_code):
|
||||
|
|
@ -684,6 +686,19 @@ class Scaffold:
|
|||
else:
|
||||
return exc_class, None
|
||||
|
||||
def ensure_sync(self, func):
|
||||
"""Ensure that the returned function is sync and calls the async func.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
Override if you wish to change how asynchronous functions are
|
||||
run.
|
||||
"""
|
||||
if iscoroutinefunction(func):
|
||||
return run_async(func)
|
||||
else:
|
||||
return func
|
||||
|
||||
|
||||
def _endpoint_from_view_func(view_func):
|
||||
"""Internal helper that returns the default endpoint for a given
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue