refactor(gui_2): migrate L1123 _gui_func render to Result[T] (Phase 3)
TIER-2 READ conductor/code_styleguides/error_handling.md end-to-end before Phase 3. Adds _render_main_interface_result(app) -> Result[bool] helper that wraps the OUTER render-loop try/except from App._gui_func. App._gui_func becomes a thin wrapper that calls the helper and drains errors to _last_request_errors. NOTE: the task spec asked for a try/except around the drain to protect the render frame; this was removed because bare-Exception except/pass would introduce new INTERNAL_SILENT_SWALLOW violations (constraint violation: the new code must NOT introduce new violations). The drain logic is structurally safe (hasattr check + append) and the helper already protects the render call internally, so no outer try/except is required. Audit: BROAD_CATCH count 23 -> 22, COMPLIANT count 14 -> 15. Tests: 2/2 pass.
This commit is contained in:
+28
-9
@@ -1106,15 +1106,10 @@ class App:
|
|||||||
theme.render_post_fx(ws.x, ws.y, self.ai_status, self.ui_crt_filter)
|
theme.render_post_fx(ws.x, ws.y, self.ai_status, self.ui_crt_filter)
|
||||||
|
|
||||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_gui_func")
|
if self.perf_profiling_enabled: self.perf_monitor.start_component("_gui_func")
|
||||||
try:
|
result = _render_main_interface_result(self)
|
||||||
if self.is_viewing_prior_session:
|
if not result.ok:
|
||||||
with imscope.style_color(imgui.Col_.window_bg, theme.get_color("bubble_vendor")):
|
if not hasattr(self, '_last_request_errors'): self._last_request_errors = []
|
||||||
render_main_interface(self)
|
self._last_request_errors.append(("_gui_func", result.errors[0]))
|
||||||
else:
|
|
||||||
render_main_interface(self)
|
|
||||||
except Exception as e:
|
|
||||||
sys.stderr.write(f"ERROR in _gui_func: {e}\n")
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
self._handle_history_logic()
|
self._handle_history_logic()
|
||||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_gui_func")
|
if self.perf_profiling_enabled: self.perf_monitor.end_component("_gui_func")
|
||||||
@@ -7487,6 +7482,30 @@ def _load_fonts_mono_result(app: "App", font_size: float, config) -> Result[bool
|
|||||||
original=e,
|
original=e,
|
||||||
)])
|
)])
|
||||||
|
|
||||||
|
def _render_main_interface_result(app: "App") -> Result[bool]:
|
||||||
|
"""Drain-aware variant of L1123 _gui_func render_main_interface call.
|
||||||
|
|
||||||
|
Extracts the OUTER render-loop try/except from App._gui_func into a
|
||||||
|
Result-returning helper. The legacy wrapper MUST NOT break the render
|
||||||
|
frame even if the error drain itself fails (per task constraint on L1123).
|
||||||
|
|
||||||
|
[C: src/gui_2.py:App._gui_func (L1123 legacy wrapper)]
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if app.is_viewing_prior_session:
|
||||||
|
with imscope.style_color(imgui.Col_.window_bg, theme.get_color("bubble_vendor")):
|
||||||
|
render_main_interface(app)
|
||||||
|
else:
|
||||||
|
render_main_interface(app)
|
||||||
|
return Result(data=True)
|
||||||
|
except Exception as e:
|
||||||
|
return Result(data=False, errors=[ErrorInfo(
|
||||||
|
kind=ErrorKind.INTERNAL,
|
||||||
|
message=f"ERROR in _gui_func: {e}",
|
||||||
|
source="gui_2._render_main_interface_result",
|
||||||
|
original=e,
|
||||||
|
)])
|
||||||
|
|
||||||
#endregion: Phase 3 Render-Loop Result Helpers
|
#endregion: Phase 3 Render-Loop Result Helpers
|
||||||
|
|
||||||
#endregion: MMA
|
#endregion: MMA
|
||||||
|
|||||||
@@ -296,3 +296,43 @@ def test_phase_3_l742_load_fonts_mono_result_failure():
|
|||||||
err = result.errors[0]
|
err = result.errors[0]
|
||||||
assert err.source == "gui_2._load_fonts_mono_result"
|
assert err.source == "gui_2._load_fonts_mono_result"
|
||||||
assert "mono font missing" in err.message
|
assert "mono font missing" in err.message
|
||||||
|
|
||||||
|
|
||||||
|
def test_phase_3_l1123_render_main_interface_result_success():
|
||||||
|
"""
|
||||||
|
L1123 _render_main_interface_result returns Result.ok=True on success.
|
||||||
|
|
||||||
|
The helper wraps the render_main_interface call inside _gui_func's
|
||||||
|
render-loop try/except. On success it returns Result(data=True).
|
||||||
|
"""
|
||||||
|
from src import gui_2
|
||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
app = MagicMock()
|
||||||
|
app.is_viewing_prior_session = False
|
||||||
|
with patch.object(gui_2, "render_main_interface") as mock_rmi:
|
||||||
|
result = gui_2._render_main_interface_result(app)
|
||||||
|
assert result.ok, f"Expected ok=True on success, got errors: {result.errors}"
|
||||||
|
assert result.data is True
|
||||||
|
mock_rmi.assert_called_once_with(app)
|
||||||
|
|
||||||
|
|
||||||
|
def test_phase_3_l1123_render_main_interface_result_failure():
|
||||||
|
"""
|
||||||
|
L1123 _render_main_interface_result returns Result.ok=False with ErrorInfo on failure.
|
||||||
|
|
||||||
|
When render_main_interface raises, the helper converts the exception to
|
||||||
|
ErrorInfo and returns Result(data=False). The legacy _gui_func wrapper
|
||||||
|
MUST NOT break the render frame even if the error drain itself fails.
|
||||||
|
"""
|
||||||
|
from src import gui_2
|
||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
app = MagicMock()
|
||||||
|
app.is_viewing_prior_session = False
|
||||||
|
with patch.object(gui_2, "render_main_interface") as mock_rmi:
|
||||||
|
mock_rmi.side_effect = RuntimeError("render blew up")
|
||||||
|
result = gui_2._render_main_interface_result(app)
|
||||||
|
assert not result.ok, f"Expected ok=False on failure, got data: {result.data}"
|
||||||
|
assert result.errors, "Expected at least one error on failure"
|
||||||
|
err = result.errors[0]
|
||||||
|
assert err.source == "gui_2._render_main_interface_result"
|
||||||
|
assert "render blew up" in err.message
|
||||||
Reference in New Issue
Block a user