mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-07-04 21:03:15 +02:00
Split diet_guard/_gatelock.py, wake_alarm/_alarm.py, and the usage_report.py/_usage_report_parsing.py pair into focused sub-modules so every Python file is <= 500 lines, satisfying test_file_length.py. Install python-kasa into .venv (declared in requirements but missing after the 3.13->3.14 venv upgrade), fixing 8 failing smart_plug tests and restoring 100% coverage. Also includes prior in-progress work from the working tree: the wake_alarm Progress/View/Hardware field-grouping refactor, brother_printer query module + tests, diet_guard foodbank/state/cli updates, new shared coerce/logging_setup helpers, morning_routine orchestrator tweaks, dwm window-manager config, gaming scripts, and misc maintenance/digital-wellbeing script updates. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
83 lines
2.9 KiB
Python
83 lines
2.9 KiB
Python
"""Session-start display-readiness probing for the diet_guard gate.
|
|
|
|
Standalone infrastructure split out of :mod:`._gatelock` to keep that module
|
|
focused on the gate window itself. The gate's systemd timer fires the instant
|
|
the user systemd instance starts (``Persistent=true`` catch-up of the slot
|
|
missed while the PC was off), which on a fresh login can BEAT the display
|
|
manager writing ``~/.Xauthority`` and the X server becoming reachable. That
|
|
race -- not the slot logic -- silently dropped the session-start launch: the Tk
|
|
root raised ``TclError`` ("couldn't connect to display") and the oneshot
|
|
service died. So before building the window the launcher polls here until the
|
|
display is connectable; on timeout the gate exits cleanly and the next timer
|
|
tick retries, instead of crashing.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import time
|
|
import tkinter as tk
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Callable
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
_DISPLAY_WAIT_TIMEOUT_S = 60.0
|
|
_DISPLAY_POLL_INTERVAL_S = 1.0
|
|
|
|
|
|
def _display_is_ready() -> bool:
|
|
"""Return True if a Tk root can connect to the X display right now.
|
|
|
|
Builds and immediately destroys a throwaway, unmapped root -- the cheapest
|
|
way to ask "is DISPLAY reachable and authorized?" without opening a visible
|
|
window. A missing display or a not-yet-written X auth cookie raises
|
|
``tk.TclError``, which is reported here as not-ready.
|
|
"""
|
|
try:
|
|
probe = tk.Tk()
|
|
except tk.TclError:
|
|
return False
|
|
probe.destroy()
|
|
return True
|
|
|
|
|
|
def wait_for_display(
|
|
*,
|
|
timeout_s: float = _DISPLAY_WAIT_TIMEOUT_S,
|
|
interval_s: float = _DISPLAY_POLL_INTERVAL_S,
|
|
sleep: Callable[[float], None] = time.sleep,
|
|
monotonic: Callable[[], float] = time.monotonic,
|
|
) -> bool:
|
|
"""Block until the X display is connectable, or ``timeout_s`` elapses.
|
|
|
|
Absorbs the session-start race in which the gate's timer fires before the
|
|
display manager has finished writing the X auth cookie (see the module
|
|
note). ``sleep`` and ``monotonic`` are injectable so the wait is tested
|
|
without real time passing.
|
|
|
|
Args:
|
|
timeout_s: Total seconds to keep retrying before giving up.
|
|
interval_s: Seconds to wait between connection probes.
|
|
sleep: Sleep function (injected in tests).
|
|
monotonic: Monotonic clock (injected in tests).
|
|
|
|
Returns:
|
|
True as soon as a probe connects; False if the deadline passes with the
|
|
display still unreachable (the caller should defer to the next tick).
|
|
"""
|
|
deadline = monotonic() + timeout_s
|
|
while True:
|
|
if _display_is_ready():
|
|
return True
|
|
if monotonic() >= deadline:
|
|
_logger.warning(
|
|
"X display unreachable after %.0fs (session still settling?); "
|
|
"deferring the gate to the next timer tick",
|
|
timeout_s,
|
|
)
|
|
return False
|
|
sleep(interval_s)
|