allow async signal receivers

This commit is contained in:
pgjones 2023-04-10 10:21:13 +01:00 committed by David Lord
parent a05c0c6b72
commit 8239765a44
No known key found for this signature in database
GPG key ID: 7A1C87E3F5BC42A8
5 changed files with 25 additions and 12 deletions

View file

@ -30,6 +30,7 @@ Unreleased
decorated function if locking is needed. :issue:`4993` decorated function if locking is needed. :issue:`4993`
- Signals are always available. ``blinker>=1.6.2`` is a required dependency. The - Signals are always available. ``blinker>=1.6.2`` is a required dependency. The
``signals_available`` attribute is deprecated. :issue:`5056` ``signals_available`` attribute is deprecated. :issue:`5056`
- Signals support ``async`` subscriber functions. :pr:`5049`
- Remove uses of locks that could cause requests to block each other very briefly. - Remove uses of locks that could cause requests to block each other very briefly.
:issue:`4993` :issue:`4993`
- Use modern packaging metadata with ``pyproject.toml`` instead of ``setup.cfg``. - Use modern packaging metadata with ``pyproject.toml`` instead of ``setup.cfg``.

View file

@ -1389,7 +1389,7 @@ class Flask(Scaffold):
.. versionadded:: 0.3 .. versionadded:: 0.3
""" """
exc_info = sys.exc_info() exc_info = sys.exc_info()
got_request_exception.send(self, exception=e) got_request_exception.send(self, _async_wrapper=self.ensure_sync, exception=e)
propagate = self.config["PROPAGATE_EXCEPTIONS"] propagate = self.config["PROPAGATE_EXCEPTIONS"]
if propagate is None: if propagate is None:
@ -1493,7 +1493,7 @@ class Flask(Scaffold):
self._got_first_request = True self._got_first_request = True
try: try:
request_started.send(self) request_started.send(self, _async_wrapper=self.ensure_sync)
rv = self.preprocess_request() rv = self.preprocess_request()
if rv is None: if rv is None:
rv = self.dispatch_request() rv = self.dispatch_request()
@ -1521,7 +1521,9 @@ class Flask(Scaffold):
response = self.make_response(rv) response = self.make_response(rv)
try: try:
response = self.process_response(response) response = self.process_response(response)
request_finished.send(self, response=response) request_finished.send(
self, _async_wrapper=self.ensure_sync, response=response
)
except Exception: except Exception:
if not from_error_handler: if not from_error_handler:
raise raise
@ -2052,7 +2054,7 @@ class Flask(Scaffold):
for func in reversed(self.teardown_request_funcs[name]): for func in reversed(self.teardown_request_funcs[name]):
self.ensure_sync(func)(exc) self.ensure_sync(func)(exc)
request_tearing_down.send(self, exc=exc) request_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc)
def do_teardown_appcontext( def do_teardown_appcontext(
self, exc: t.Optional[BaseException] = _sentinel # type: ignore self, exc: t.Optional[BaseException] = _sentinel # type: ignore
@ -2077,7 +2079,7 @@ class Flask(Scaffold):
for func in reversed(self.teardown_appcontext_funcs): for func in reversed(self.teardown_appcontext_funcs):
self.ensure_sync(func)(exc) self.ensure_sync(func)(exc)
appcontext_tearing_down.send(self, exc=exc) appcontext_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc)
def app_context(self) -> AppContext: def app_context(self) -> AppContext:
"""Create an :class:`~flask.ctx.AppContext`. Use as a ``with`` """Create an :class:`~flask.ctx.AppContext`. Use as a ``with``

View file

@ -242,7 +242,7 @@ class AppContext:
def push(self) -> None: def push(self) -> None:
"""Binds the app context to the current context.""" """Binds the app context to the current context."""
self._cv_tokens.append(_cv_app.set(self)) self._cv_tokens.append(_cv_app.set(self))
appcontext_pushed.send(self.app) appcontext_pushed.send(self.app, _async_wrapper=self.app.ensure_sync)
def pop(self, exc: t.Optional[BaseException] = _sentinel) -> None: # type: ignore def pop(self, exc: t.Optional[BaseException] = _sentinel) -> None: # type: ignore
"""Pops the app context.""" """Pops the app context."""
@ -260,7 +260,7 @@ class AppContext:
f"Popped wrong app context. ({ctx!r} instead of {self!r})" f"Popped wrong app context. ({ctx!r} instead of {self!r})"
) )
appcontext_popped.send(self.app) appcontext_popped.send(self.app, _async_wrapper=self.app.ensure_sync)
def __enter__(self) -> "AppContext": def __enter__(self) -> "AppContext":
self.push() self.push()

View file

@ -327,8 +327,10 @@ def flash(message: str, category: str = "message") -> None:
flashes = session.get("_flashes", []) flashes = session.get("_flashes", [])
flashes.append((category, message)) flashes.append((category, message))
session["_flashes"] = flashes session["_flashes"] = flashes
app = current_app._get_current_object() # type: ignore
message_flashed.send( message_flashed.send(
current_app._get_current_object(), # type: ignore app,
_async_wrapper=app.ensure_sync,
message=message, message=message,
category=category, category=category,
) )

View file

@ -126,9 +126,13 @@ class DispatchingJinjaLoader(BaseLoader):
def _render(app: "Flask", template: Template, context: t.Dict[str, t.Any]) -> str: def _render(app: "Flask", template: Template, context: t.Dict[str, t.Any]) -> str:
app.update_template_context(context) app.update_template_context(context)
before_render_template.send(app, template=template, context=context) before_render_template.send(
app, _async_wrapper=app.ensure_sync, template=template, context=context
)
rv = template.render(context) rv = template.render(context)
template_rendered.send(app, template=template, context=context) template_rendered.send(
app, _async_wrapper=app.ensure_sync, template=template, context=context
)
return rv return rv
@ -163,11 +167,15 @@ def _stream(
app: "Flask", template: Template, context: t.Dict[str, t.Any] app: "Flask", template: Template, context: t.Dict[str, t.Any]
) -> t.Iterator[str]: ) -> t.Iterator[str]:
app.update_template_context(context) app.update_template_context(context)
before_render_template.send(app, template=template, context=context) before_render_template.send(
app, _async_wrapper=app.ensure_sync, template=template, context=context
)
def generate() -> t.Iterator[str]: def generate() -> t.Iterator[str]:
yield from template.generate(context) yield from template.generate(context)
template_rendered.send(app, template=template, context=context) template_rendered.send(
app, _async_wrapper=app.ensure_sync, template=template, context=context
)
rv = generate() rv = generate()