"""Persistent session-state helpers for GUI-only runtime preferences.""" from __future__ import annotations from dataclasses import dataclass import json import logging from pathlib import Path logger = logging.getLogger(__name__) @dataclass(slots=True) class GuiSessionState: """Small persisted GUI session state.""" last_profile_path: str = "" class GuiSessionStateStore: """Atomic JSON store for GUI session-state file.""" def __init__(self, path: Path) -> None: """Create store targeting `path`.""" self._path = path self._path.parent.mkdir(parents=True, exist_ok=True) @property def path(self) -> Path: """Return backing session-state file path.""" return self._path def load(self) -> GuiSessionState: """Load session-state from disk or return empty defaults when missing.""" if not self._path.exists(): return GuiSessionState() try: payload = json.loads(self._path.read_text(encoding="utf-8")) except (OSError, json.JSONDecodeError) as exc: # The state file is GUI-local cache — a corrupted file should not # prevent the app from starting. Reset to defaults and let the # next write overwrite it. logger.warning("Resetting unreadable GUI session-state %s: %s", self._path, exc) return GuiSessionState() if not isinstance(payload, dict): logger.warning("Resetting GUI session-state with non-object root: %s", self._path) return GuiSessionState() raw_path = payload.get("last_profile_path", "") if not isinstance(raw_path, str): logger.warning("Resetting GUI session-state with non-string last_profile_path: %s", self._path) return GuiSessionState() return GuiSessionState(last_profile_path=raw_path) def write(self, state: GuiSessionState) -> Path: """Atomically write session-state JSON file.""" temp_path = self._path.with_suffix(self._path.suffix + ".tmp") temp_path.write_text( json.dumps({"last_profile_path": state.last_profile_path}, indent=2), encoding="utf-8", ) temp_path.replace(self._path) logger.debug("Wrote GUI session-state to %s", self._path) return self._path