Coverage for src / lilbee / cli / tui / thread_safe.py: 100%
10 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-04-29 19:16 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-04-29 19:16 +0000
1"""Thread-safe helpers for posting from @work(thread=True) workers to the main thread.
3Textual's call_from_thread raises OSError when the app's message queue
4has already been closed during shutdown. Since workers run in daemon
5threads, they can outlive the app. This module provides a drop-in
6wrapper that silently drops calls when the app is gone.
7"""
9from __future__ import annotations
11import logging
12from typing import Any
14from textual.dom import DOMNode
16log = logging.getLogger(__name__)
19def call_from_thread(node: DOMNode, fn: Any, *args: Any, **kwargs: Any) -> None:
20 """Post *fn* to the main thread via the app.
22 Drops the call (does not crash the worker) when the target node's app
23 is no longer reachable, e.g. during shutdown or after a screen was
24 replaced. Logs at debug so the drop is discoverable without leaking
25 warning text into the TUI render (textual's log handler routes
26 stderr into the rendered frame). Long-running workers that must
27 survive a screen switch should own their state on the app
28 (TaskBarController pattern in widgets/task_bar.py) rather than
29 relying on this wrapper.
30 """
31 try:
32 node.app.call_from_thread(fn, *args, **kwargs)
33 except Exception as exc:
34 log.debug(
35 "call_from_thread dropped %s: %s",
36 getattr(fn, "__name__", fn),
37 exc,
38 )