screen-locker/scripts/_xvfb_reexec.py
Krzysztof kuhy Rudnicki 76a4c6a0a7 Finish the Python side: scripts, conftest, and the last test modules
verify_lock_popup_safety.py (318) -> _xvfb_reexec.py      shared re-exec
                                       _popup_form_check.py HostileLock, ticks,
                                                            the real-form check
  verify_screen_fits.py (266)       -> uses _xvfb_reexec too
  conftest.py (329)                 -> _tk_mocks.py         the tk mock + the
                                                            module patch list
                                       _opt_in_fixtures.py  requestable fixtures
  three test modules                -> _part4/_part5/_part15 siblings

conftest keeps every autouse fixture. pytest applies autouse fixtures from
conftest only, so one moved to a sibling would silently stop running and take
its safety guard with it -- verified by asserting the fixtures are still
listed, not just that the suite is green. The five near-identical _isolate_*
fixtures collapse into one table-driven _isolate_state_files, which also picks
up the _shutdown_sick_state binding an earlier split created.

scripts/ becomes a real package so the shared helpers are importable. Both
gates now run as `python3 -m scripts.<name>`, including CI -- the path form put
scripts/ on sys.path instead of the repo root, and the alternative was a
try/except ImportError that this repo's no-silent-failures hook rightly
rejects. Each gate was run in its exact invocation form.

Note: verify_lock_popup_safety still fails on
`RecoveryLoop.__init__() takes 3 positional arguments but 6 were given`. That
is pre-existing -- confirmed by running it at HEAD in a clean worktree before
touching it -- a gatelock API drift, not this refactor. Left as found.

978 tests at 100% branch coverage. Gate: 41 -> 22 files, all remaining ones
Dart plus DESIGN_AUDIT_TODO.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EveB813BQ8abAP68VSqZ5Y
2026-08-15 20:57:29 +02:00

73 lines
2.4 KiB
Python

"""Re-run a GUI check script on a throwaway X display.
Split out of ``verify_lock_popup_safety.py`` and ``verify_screen_fits.py``
to keep every file under the 250-line cap. Both had their own near-identical
copy; they differ only in the sentinel env var and how the inner process is
addressed, so both are parameters here.
Each script runs itself twice: the outer run starts ``xvfb-run`` and re-execs,
the inner run (marked by the sentinel) does the real work against that
display. Without the sentinel the inner process would start another Xvfb
forever.
"""
from __future__ import annotations
import logging
import os
from pathlib import Path
import shutil
import subprocess
import sys
_logger = logging.getLogger(__name__)
# Comfortably bigger than every size under test, so each surface is sized by
# the geometry the harness sets rather than clamped by the display.
_SCREEN_ARG = "-screen 0 1600x1200x24"
def reexec_under_xvfb(
*,
inner_env: str,
module: str | None = None,
script: Path | None = None,
) -> int:
"""Re-run this check on a throwaway X display, returning its exit code.
Exactly one of *module* (run as ``python -m module`` from the repo root)
or *script* (run as an absolute path) identifies the inner process; that
difference is why the two callers cannot share a single hardcoded form.
Args:
inner_env: Sentinel env var set for the inner run, so it knows not to
start another Xvfb.
module: Dotted module path to run with ``-m``.
script: Absolute path of the script file to run.
Returns:
The inner process's exit code, or 1 if ``xvfb-run`` is unavailable.
"""
if (module is None) == (script is None):
msg = "pass exactly one of module= or script="
raise ValueError(msg)
xvfb_run = shutil.which("xvfb-run")
if xvfb_run is None:
_logger.error(
"xvfb-run not found. Install it with: sudo pacman -S --needed "
"xorg-server-xvfb"
)
return 1
env = dict(os.environ, **{inner_env: "1"})
repo_root = Path(__file__).resolve().parent.parent
# Absolute argv, no shell.
target = ["-m", module] if module is not None else [str(script)]
return subprocess.run(
[xvfb_run, "-a", "-s", _SCREEN_ARG, sys.executable, *target],
check=False,
cwd=repo_root,
env=env,
).returncode