Private
Public Access
0
0

docs(gui_2): __getattr__ hasattr-guard + startup architecture section

Critical fix:
- Update __getattr__ code example to show the current bcdc26d0 version
  (with hasattr guard); old example showed the silent-None bug version

New section 'Startup Architecture (Lazy Imports, Profiler, Refresh Rate)':
- _LazyModule proxies (np, filedialog, Tk, win32gui, win32con)
- _FiledialogStub for headless/tkinter-less envs
- startup_profiler + render_warmup_status_indicator (defer_warmup=True)
- Native _detect_refresh_rate_win32 (ctypes.EnumDisplaySettingsW)
- immapp.run try/except error handling (native 0xc0000005 graceful degrade)
This commit is contained in:
2026-06-10 19:52:11 -04:00
parent 5aa19e59e7
commit c501035609
+16 -2
View File
@@ -429,7 +429,9 @@ The `App` class (around line 478-487) defines two descriptor hooks that delegate
def __getattr__(self, name: str) -> Any:
if name == 'controller':
raise AttributeError(name)
return getattr(self.controller, name)
if hasattr(self, 'controller') and hasattr(self.controller, name):
return getattr(self.controller, name)
raise AttributeError(name)
def __setattr__(self, name: str, value: Any) -> None:
if name != 'controller' and hasattr(self, 'controller') and hasattr(self.controller, name):
@@ -438,6 +440,8 @@ def __setattr__(self, name: str, value: Any) -> None:
object.__setattr__(self, name, value)
```
> **Critical (bcdc26d0):** The current code includes the `hasattr(self.controller, name)` guard in `__getattr__`. The previous version (without this guard) was a silent-None bug: any uninitialized `ui_` attribute on the App would have called `getattr(self.controller, name)` → raised `AttributeError` from Python → the ImGui code would catch that and return `None` → the GUI would render blanks silently instead of crashing. The `hasattr` guard makes the `AttributeError` propagate correctly so the bug surfaces during development. The fix is in `src/gui_2.py:688-693`.
**Why this matters:**
- The `Controller` is the single source of truth for settable state (e.g. `ui_ai_input`, `ui_separate_tier1`, `show_windows`, `temperature`).
- The `App` is a thin view layer that delegates reads (`__getattr__`) and writes (`__setattr__`) to the Controller.
@@ -461,9 +465,19 @@ uv run python -c "import ast; tree = ast.parse(open('src/gui_2.py').read()); [pr
**How to fix:** Re-indent the affected method to 2-space class level. This bit the project in 2026-06-05 during a cleanup commit: `_capture_workspace_profile` was being parsed as nested inside `_apply_snapshot` due to a 1-space indentation drift, breaking 3 live_gui tests (test_auto_switch_sim, test_workspace_profiles_restoration, test_undo_redo_lifecycle).
---
### Startup Architecture (Lazy Imports, Profiler, Refresh Rate)
The 2026-06-06 `startup_speedup_20260606` track restructured `gui_2.py` for ~2400ms faster startup. The key components:
**`_LazyModule` proxies** (`np`, `filedialog`, `Tk`, `win32gui`, `win32con`): Defer `import numpy`, `import tkinter.filedialog`, `import tkinter`, `import win32gui`, `import win32con` until first attribute access. The first `gui_2` import drops from ~1770ms to ~341ms.
**`_FiledialogStub`**: No-op fallback for tkinter-less environments (e.g., headless CI). Sets `available = False` so the GUI can detect and skip file dialogs gracefully.
**`startup_profiler` + `render_warmup_status_indicator(app)`**: `AppController(defer_warmup=True)` defers heavy SDK warmup (google.genai, anthropic, openai, fastapi) to a background thread. `startup_profiler.phase(name)` wraps each init phase and reports per-phase duration. `render_warmup_status_indicator` is called per-frame during the warmup window to show a progress indicator in the UI. The warmup completes asynchronously; `_on_warmup_complete_callback` is invoked when done. See [guide_architecture.md](guide_architecture.md#warmup-architecture) for the full mechanism.
**Native refresh rate detection** (`_detect_refresh_rate_win32`): The old implementation used a PowerShell/WMI subprocess (~350ms blocking). The new implementation uses `ctypes.windll.user32.EnumDisplaySettingsW` directly (~0.3ms, 1000x faster). Used by the ImGui IO setup to set the display refresh rate.
**`immapp.run` error handling**: `immapp.run` is wrapped in try/except catching `RuntimeError` from native ImGui bundle assertions. On native crash, `_gui_degraded_reason` and `_last_imgui_assert` are set on the controller, and the GUI enters a degraded mode (rendering a static error panel instead of the live UI). This prevents the Python process from being killed by an uncatchable Windows access violation (`0xc0000005`).
---