python3-quart: update to 0.19.3.

Closes: #46736 [via git-merge-pr]
This commit is contained in:
Andrew J. Hesford 2023-10-17 10:04:50 -04:00
parent 35ccd5d9f9
commit decc1999e9
2 changed files with 7 additions and 366 deletions

View File

@ -1,360 +0,0 @@
From c9b555ff284bb54a45adab44c8e6d78ab8713da0 Mon Sep 17 00:00:00 2001
From: pgjones <philip.graham.jones@googlemail.com>
Date: Sun, 9 Apr 2023 16:57:26 +0100
Subject: [PATCH] Upgrade to blinker 1.6
This allows the custom signal implementation to be removed and for
sync signal receivers to be supported in the same manner as sync route
handlers.
---
pyproject.toml | 2 +-
src/quart/app.py | 38 +++++++++++++++++++++-----------
src/quart/asgi.py | 4 ++--
src/quart/ctx.py | 4 ++--
src/quart/helpers.py | 5 +++--
src/quart/signals.py | 48 ++---------------------------------------
src/quart/templating.py | 16 ++++++++++----
tests/test_signals.py | 37 -------------------------------
8 files changed, 48 insertions(+), 106 deletions(-)
delete mode 100644 tests/test_signals.py
diff --git a/pyproject.toml b/pyproject.toml
index da35a647..9d4876a0 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -27,7 +27,7 @@
[tool.poetry.dependencies]
python = ">=3.7"
aiofiles = "*"
-blinker = "<1.6"
+blinker = ">=1.6"
click = ">=8.0.0"
hypercorn = ">=0.11.2"
importlib_metadata = { version = "*", python = "<3.10" }
diff --git a/src/quart/app.py b/src/quart/app.py
index 8ee111a7..e3d3cc0f 100644
--- a/src/quart/app.py
+++ b/src/quart/app.py
@@ -1113,7 +1113,9 @@
By default this switches the error response to a 500 internal
server error.
"""
- await got_request_exception.send(self, exception=error)
+ await got_request_exception.send_async(
+ self, _sync_wrapper=self.ensure_async, exception=error
+ )
self.log_exception(sys.exc_info())
@@ -1138,7 +1140,9 @@
By default this logs the exception and then re-raises it.
"""
- await got_websocket_exception.send(self, exception=error)
+ await got_websocket_exception.send_async(
+ self, _sync_wrapper=self.ensure_async, exception=error
+ )
self.log_exception(sys.exc_info())
@@ -1245,7 +1249,7 @@
for function in self.teardown_request_funcs[name]:
await self.ensure_async(function)(exc)
- await request_tearing_down.send(self, exc=exc)
+ await request_tearing_down.send_async(self, _sync_wrapper=self.ensure_async, exc=exc)
async def do_teardown_websocket(
self, exc: Optional[BaseException], websocket_context: Optional[WebsocketContext] = None
@@ -1263,13 +1267,13 @@
for function in self.teardown_websocket_funcs[name]:
await self.ensure_async(function)(exc)
- await websocket_tearing_down.send(self, exc=exc)
+ await websocket_tearing_down.send_async(self, _sync_wrapper=self.ensure_async, exc=exc)
async def do_teardown_appcontext(self, exc: Optional[BaseException]) -> None:
"""Teardown the app (context), calling the teardown functions."""
for function in self.teardown_appcontext_funcs:
await self.ensure_async(function)(exc)
- await appcontext_tearing_down.send(self, exc=exc)
+ await appcontext_tearing_down.send_async(self, _sync_wrapper=self.ensure_async, exc=exc)
def app_context(self) -> AppContext:
"""Create and return an app context.
@@ -1558,7 +1562,9 @@
self.background_tasks.add(task)
async def handle_background_exception(self, error: Exception) -> None:
- await got_background_exception.send(self, exception=error)
+ await got_background_exception.send_async(
+ self, _sync_wrapper=self.ensure_async, exception=error
+ )
self.log_exception(sys.exc_info())
@@ -1666,7 +1672,7 @@
omits this argument.
"""
await self.try_trigger_before_first_request_functions()
- await request_started.send(self)
+ await request_started.send_async(self, _sync_wrapper=self.ensure_async)
try:
result = await self.preprocess_request(request_context)
if result is None:
@@ -1733,7 +1739,9 @@
response = await self.make_response(result)
try:
response = await self.process_response(response, request_context)
- await request_finished.send(self, response=response)
+ await request_finished.send_async(
+ self, _sync_wrapper=self.ensure_async, response=response
+ )
except Exception:
if not from_error_handler:
raise
@@ -1787,7 +1795,7 @@
the Flask convention.
"""
await self.try_trigger_before_first_request_functions()
- await websocket_started.send(self)
+ await websocket_started.send_async(self, _sync_wrapper=self.ensure_async)
try:
result = await self.preprocess_websocket(websocket_context)
if result is None:
@@ -1857,7 +1865,9 @@
response = None
try:
response = await self.postprocess_websocket(response, websocket_context)
- await websocket_finished.send(self, response=response)
+ await websocket_finished.send_async(
+ self, _sync_wrapper=self.ensure_async, response=response
+ )
except Exception:
if not from_error_handler:
raise
@@ -1937,7 +1947,9 @@
for gen in self.while_serving_gens:
await gen.__anext__()
except Exception as error:
- await got_serving_exception.send(self, exception=error)
+ await got_serving_exception.send_async(
+ self, _sync_wrapper=self.ensure_async, exception=error
+ )
self.log_exception(sys.exc_info())
raise
@@ -1954,7 +1966,9 @@
else:
raise RuntimeError("While serving generator didn't terminate")
except Exception as error:
- await got_serving_exception.send(self, exception=error)
+ await got_serving_exception.send_async(
+ self, _sync_wrapper=self.ensure_async, exception=error
+ )
self.log_exception(sys.exc_info())
raise
diff --git a/src/quart/asgi.py b/src/quart/asgi.py
index ba266dc3..2725af8d 100644
--- a/src/quart/asgi.py
+++ b/src/quart/asgi.py
@@ -169,7 +169,7 @@ async def handle_messages(self, receive: ASGIReceiveCallable) -> None:
event = await receive()
if event["type"] == "websocket.receive":
message = event.get("bytes") or event["text"]
- await websocket_received.send(message)
+ await websocket_received.send_async(message)
await self.queue.put(message)
elif event["type"] == "websocket.disconnect":
return
@@ -261,7 +261,7 @@ async def send_data(self, send: ASGISendCallable, data: AnyStr) -> None:
await send({"type": "websocket.send", "bytes": None, "text": data})
else:
await send({"type": "websocket.send", "bytes": data, "text": None})
- await websocket_sent.send(data)
+ await websocket_sent.send_async(data)
async def accept_connection(
self, send: ASGISendCallable, headers: Headers, subprotocol: Optional[str]
diff --git a/src/quart/ctx.py b/src/quart/ctx.py
index 806aff74..c92ba92e 100644
--- a/src/quart/ctx.py
+++ b/src/quart/ctx.py
@@ -240,7 +240,7 @@ def copy(self) -> "AppContext":
async def push(self) -> None:
self._cv_tokens.append(_cv_app.set(self))
- await appcontext_pushed.send(self.app)
+ await appcontext_pushed.send_async(self.app, _sync_wrapper=self.app.ensure_async)
async def pop(self, exc: Optional[BaseException] = _sentinel) -> None: # type: ignore
try:
@@ -255,7 +255,7 @@ async def pop(self, exc: Optional[BaseException] = _sentinel) -> None: # type:
if ctx is not self:
raise AssertionError(f"Popped wrong app context. ({ctx!r} instead of {self!r})")
- await appcontext_popped.send(self.app)
+ await appcontext_popped.send_async(self.app, _sync_wrapper=self.app.ensure_async)
async def __aenter__(self) -> "AppContext":
await self.push()
diff --git a/src/quart/helpers.py b/src/quart/helpers.py
index c848a72f..0491acfe 100644
--- a/src/quart/helpers.py
+++ b/src/quart/helpers.py
@@ -113,8 +113,9 @@ async def login():
flashes = session.get("_flashes", [])
flashes.append((category, message))
session["_flashes"] = flashes
- await message_flashed.send(
- current_app._get_current_object(), message=message, category=category # type: ignore
+ app = current_app._get_current_object() # type: ignore
+ await message_flashed.send_async(
+ app, _sync_wrapper=app.ensure_async, message=message, category=category
)
diff --git a/src/quart/signals.py b/src/quart/signals.py
index a23b902d..de5e9fcc 100644
--- a/src/quart/signals.py
+++ b/src/quart/signals.py
@@ -1,54 +1,10 @@
from __future__ import annotations
-from functools import wraps
-from typing import Any, Callable, List, Optional, Tuple
-
-from blinker import NamedSignal, Namespace # type: ignore[import]
-
-from .utils import is_coroutine_function
+from blinker import Namespace
signals_available = True
-
-class AsyncNamedSignal(NamedSignal): # type: ignore
- def __init__(self, name: str, doc: Optional[str] = None) -> None:
- super().__init__(name, doc)
-
- async def send(self, *sender: Any, **kwargs: Any) -> List[Tuple[Callable, Any]]:
- coroutines = super().send(*sender, **kwargs)
- result: List[Tuple[Callable, Any]] = []
- for handler, coroutine in coroutines:
- result.append((handler, await coroutine))
- return result
-
- def connect(self, receiver: Callable, *args: Any, **kwargs: Any) -> Callable:
- if is_coroutine_function(receiver):
- handler = receiver
- else:
-
- @wraps(receiver)
- async def handler(*a: Any, **k: Any) -> Any:
- return receiver(*a, **k)
-
- if handler is not receiver and kwargs.get("weak", True):
- # Blinker will take a weakref to handler, which goes out
- # of scope with this method as it is a wrapper around the
- # receiver. Whereas we'd want it to go out of scope when
- # receiver does. Therefore we can place it on the receiver
- # function. (Ideally I'll think of a better way).
- receiver._quart_wrapper_func = handler # type: ignore
- return super().connect(handler, *args, **kwargs)
-
-
-class AsyncNamespace(Namespace): # type: ignore
- def signal(self, name: str, doc: Optional[str] = None) -> AsyncNamedSignal:
- try:
- return self[name]
- except KeyError:
- return self.setdefault(name, AsyncNamedSignal(name, doc))
-
-
-_signals = AsyncNamespace()
+_signals = Namespace()
#: Called before a template is rendered, connection functions
# should have a signature of Callable[[Quart, Template, dict], None]
diff --git a/src/quart/templating.py b/src/quart/templating.py
index 416c2eef..5c07d132 100644
--- a/src/quart/templating.py
+++ b/src/quart/templating.py
@@ -116,9 +116,13 @@ async def render_template_string(source: str, **context: Any) -> str:
async def _render(template: Template, context: dict, app: "Quart") -> str:
- await before_render_template.send(app, template=template, context=context)
+ await before_render_template.send_async(
+ app, _sync_wrapper=app.ensure_async, template=template, context=context
+ )
rendered_template = await template.render_async(context)
- await template_rendered.send(app, template=template, context=context)
+ await template_rendered.send_async(
+ app, _sync_wrapper=app.ensure_async, template=template, context=context
+ )
return rendered_template
@@ -166,12 +170,16 @@ async def stream_template_string(source: str, **context: Any) -> AsyncIterator[s
async def _stream(app: "Quart", template: Template, context: Dict[str, Any]) -> AsyncIterator[str]:
- await before_render_template.send(app, template=template, context=context)
+ await before_render_template.send_async(
+ app, _sync_wrapper=app.ensure_async, template=template, context=context
+ )
async def generate() -> AsyncIterator[str]:
async for chunk in template.generate_async(context):
yield chunk
- await template_rendered.send(app, template=template, context=context)
+ await template_rendered.send_async(
+ app, _sync_wrapper=app.ensure_async, template=template, context=context
+ )
# If a request context is active, keep it while generating.
if has_request_context():
diff --git a/tests/test_signals.py b/tests/test_signals.py
deleted file mode 100644
index 671d5942..00000000
--- a/tests/test_signals.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from __future__ import annotations
-
-from typing import Any
-
-import pytest
-
-from quart.signals import AsyncNamedSignal
-
-
-@pytest.mark.parametrize("weak", [True, False])
-async def test_sync_signal(weak: bool) -> None:
- signal = AsyncNamedSignal("name")
- fired = False
-
- def sync_fired(*_: Any) -> None:
- nonlocal fired
- fired = True
-
- signal.connect(sync_fired, weak=weak)
-
- await signal.send()
- assert fired
-
-
-@pytest.mark.parametrize("weak", [True, False])
-async def test_async_signal(weak: bool) -> None:
- signal = AsyncNamedSignal("name")
- fired = False
-
- async def async_fired(*_: Any) -> None:
- nonlocal fired
- fired = True
-
- signal.connect(async_fired, weak=weak)
-
- await signal.send()
- assert fired

View File

@ -1,19 +1,20 @@
# Template file for 'python3-quart'
pkgname=python3-quart
version=0.18.4
revision=3
version=0.19.3
revision=1
build_style=python3-pep517
hostmakedepends="python3-poetry-core"
depends="python3-aiofiles python3-hypercorn python3-click python3-MarkupSafe
python3-blinker python3-itsdangerous python3-Jinja2 python3-Werkzeug"
checkdepends="python3-pytest-asyncio python3-hypothesis python3-mock python3-dotenv $depends"
depends="python3-aiofiles python3-blinker python3-click python3-Flask
python3-hypercorn python3-itsdangerous python3-Jinja2 python3-MarkupSafe
python3-Werkzeug"
checkdepends="python3-pytest-asyncio python3-hypothesis python3-dotenv $depends"
short_desc="Python asyncio ASGI web framework with Flask API"
maintainer="Andrew J. Hesford <ajh@sideband.org>"
license="MIT"
homepage="https://quart.palletsprojects.com/en/latest/"
changelog="https://raw.githubusercontent.com/pallets/quart/main/CHANGES.rst"
distfiles="https://github.com/pallets/quart/archive/refs/tags/${version}.tar.gz"
checksum=0fc5fe5c32ec94a3a12262afa56c1be143599c2a4fb02bdf7109456b61c87ac2
checksum=5f1a43e2296960c755fec3ab6144b6786614bf4602c2f52084f75d5ce0d8ad25
pre_check() {
vsed -e '/addopts/d' -i pyproject.toml