diff --git a/CHANGES.rst b/CHANGES.rst index 77190adf..e75719ee 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -30,6 +30,7 @@ Unreleased decorated function if locking is needed. :issue:`4993` - Signals are always available. ``blinker>=1.6.2`` is a required dependency. The ``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. :issue:`4993` - Use modern packaging metadata with ``pyproject.toml`` instead of ``setup.cfg``. diff --git a/src/flask/app.py b/src/flask/app.py index 3bbe1bb2..f3b2126b 100644 --- a/src/flask/app.py +++ b/src/flask/app.py @@ -1389,7 +1389,7 @@ class Flask(Scaffold): .. versionadded:: 0.3 """ 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"] if propagate is None: @@ -1493,7 +1493,7 @@ class Flask(Scaffold): self._got_first_request = True try: - request_started.send(self) + request_started.send(self, _async_wrapper=self.ensure_sync) rv = self.preprocess_request() if rv is None: rv = self.dispatch_request() @@ -1521,7 +1521,9 @@ class Flask(Scaffold): response = self.make_response(rv) try: response = self.process_response(response) - request_finished.send(self, response=response) + request_finished.send( + self, _async_wrapper=self.ensure_sync, response=response + ) except Exception: if not from_error_handler: raise @@ -2052,7 +2054,7 @@ class Flask(Scaffold): for func in reversed(self.teardown_request_funcs[name]): 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( self, exc: t.Optional[BaseException] = _sentinel # type: ignore @@ -2077,7 +2079,7 @@ class Flask(Scaffold): for func in reversed(self.teardown_appcontext_funcs): 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: """Create an :class:`~flask.ctx.AppContext`. Use as a ``with`` diff --git a/src/flask/ctx.py b/src/flask/ctx.py index c79c26dc..64a0f065 100644 --- a/src/flask/ctx.py +++ b/src/flask/ctx.py @@ -242,7 +242,7 @@ class AppContext: def push(self) -> None: """Binds the app context to the current context.""" 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 """Pops the app context.""" @@ -260,7 +260,7 @@ class AppContext: 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": self.push() diff --git a/src/flask/helpers.py b/src/flask/helpers.py index 33dc41a4..a8bf4971 100644 --- a/src/flask/helpers.py +++ b/src/flask/helpers.py @@ -327,8 +327,10 @@ def flash(message: str, category: str = "message") -> None: flashes = session.get("_flashes", []) flashes.append((category, message)) session["_flashes"] = flashes + app = current_app._get_current_object() # type: ignore message_flashed.send( - current_app._get_current_object(), # type: ignore + app, + _async_wrapper=app.ensure_sync, message=message, category=category, ) diff --git a/src/flask/templating.py b/src/flask/templating.py index edbbe930..77504c63 100644 --- a/src/flask/templating.py +++ b/src/flask/templating.py @@ -126,9 +126,13 @@ class DispatchingJinjaLoader(BaseLoader): def _render(app: "Flask", template: Template, context: t.Dict[str, t.Any]) -> str: 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) - template_rendered.send(app, template=template, context=context) + template_rendered.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) return rv @@ -163,11 +167,15 @@ def _stream( app: "Flask", template: Template, context: t.Dict[str, t.Any] ) -> t.Iterator[str]: 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]: 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()