From 5914f57ddc73a8043e030e0687af740ad262d527 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sun, 17 Aug 2025 09:27:54 +0100 Subject: [PATCH] message pump optimization --- src/textual/_queue.py | 49 +++++++++++++++++++++++++++++++++++++ src/textual/message_pump.py | 5 ++-- src/textual/widget.py | 4 +-- 3 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 src/textual/_queue.py diff --git a/src/textual/_queue.py b/src/textual/_queue.py new file mode 100644 index 0000000000..d01e96adb7 --- /dev/null +++ b/src/textual/_queue.py @@ -0,0 +1,49 @@ +from __future__ import annotations + +import asyncio +from asyncio import Event +from collections import deque +from typing import Generic, TypeVar + +QueueType = TypeVar("QueueType") + + +class Queue(Generic[QueueType]): + """A cut-down version of asyncio.Queue + + This has just enough functionality to run the message pumps. + + """ + + def __init__(self) -> None: + self.values: deque[QueueType] = deque() + self.ready_event = Event() + + def put_nowait(self, value: QueueType) -> None: + self.values.append(value) + self.ready_event.set() + + def qsize(self) -> int: + return len(self.values) + + def empty(self) -> bool: + return not self.values + + def task_done(self) -> None: + pass + + async def get(self) -> QueueType: + if not self.ready_event.is_set(): + await self.ready_event.wait() + value = self.values.popleft() + if not self.values: + self.ready_event.clear() + return value + + def get_nowait(self) -> QueueType: + if not self.values: + raise asyncio.QueueEmpty() + value = self.values.popleft() + if not self.values: + self.ready_event.clear() + return value diff --git a/src/textual/message_pump.py b/src/textual/message_pump.py index dd2ec42270..4d2f4ccf27 100644 --- a/src/textual/message_pump.py +++ b/src/textual/message_pump.py @@ -36,6 +36,7 @@ from textual._context import message_hook as message_hook_context_var from textual._context import prevent_message_types_stack from textual._on import OnNoWidget +from textual._queue import Queue from textual._time import time from textual.constants import SLOW_THRESHOLD from textual.css.match import match @@ -143,8 +144,8 @@ def __init__(self, parent: MessagePump | None = None) -> None: """ @cached_property - def _message_queue(self) -> asyncio.Queue[Message | None]: - return asyncio.Queue() + def _message_queue(self) -> Queue[Message | None]: + return Queue() @cached_property def _mounted_event(self) -> asyncio.Event: diff --git a/src/textual/widget.py b/src/textual/widget.py index 0380ae4e87..56a8980676 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -3904,12 +3904,12 @@ def post_render( return renderable - def watch_mouse_hover(self, value: bool) -> None: + def watch_mouse_hover(self, _mouse_over: bool) -> None: """Update from CSS if mouse over state changes.""" if self._has_hover_style: self._update_styles() - def watch_has_focus(self, value: bool) -> None: + def watch_has_focus(self, _has_focus: bool) -> None: """Update from CSS if has focus state changes.""" self._update_styles()