"""Guard against the crash-on-close regression. The panel's worker/monitor threads schedule Tk callbacks via _safe_after. During shutdown that .after() raises (thread + dying interpreter); if it escaped, the worker's `finally` aborted before unlinking its PID file -> stale runtime/pids/*. These asserts pin the two invariants that prevent that. Run: python test_controlpanel_close.py """ from types import SimpleNamespace from controlpanel import NexusControlPanel def _fake(closing, after_raises): def after(_delay, _fn): if after_raises: raise RuntimeError("main thread is not in main loop") return SimpleNamespace(_closing=closing, root=SimpleNamespace(after=after)) # 1. A raising .after() (teardown condition) must NOT propagate. NexusControlPanel._safe_after(_fake(closing=False, after_raises=True), 0, lambda: None) # 2. Once closing, we must not touch Tk at all — schedule is skipped. scheduled = [] obj = SimpleNamespace(_closing=True, root=SimpleNamespace(after=lambda d, f: scheduled.append(f))) NexusControlPanel._safe_after(obj, 0, lambda: None) assert scheduled == [], "closing panel must not schedule Tk callbacks" print("ok")