From 8130ae34d4c5629f2672d9f5f70c9360e2f36f6d Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sun, 7 Jun 2026 17:07:40 -0400 Subject: [PATCH] fix(gui_2): initialize ui_synthesis_prompt/selected_takes to prevent crash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sloppy.py crashed on startup at gui_2.py:4006 with TypeError: input_text_multiline(): incompatible function arguments. The second positional arg (app.ui_synthesis_prompt) was None when it should be str. Root cause: the defensive guards if not hasattr(app, 'ui_synthesis_prompt'): app.ui_synthesis_prompt = "" only fire if the attribute is MISSING — if it's set to None elsewhere (e.g. via setattr from a config flush, or a plugin side-effect), hasattr returns True and the value stays None. Fix in 3 places: 1. App.__init__: initialize ui_synthesis_prompt = "" and ui_synthesis_selected_takes = {} at construction time alongside related context state (line 456). 2. render_synthesis_panel (line ~4002): harden the guard to check isinstance(getattr(...), str) — fixes the same pattern at its first call site. 3. render_takes_panel (line ~4139): same hardening at the second call site. Verified by constructing App() in a fresh subprocess and inspecting the attributes (ui_synthesis_prompt == "" and ui_synthesis_selected_takes == {} both before and after init_state()). Manual smoke test: previously the app crashed before any window was visible; now it renders the first frame. --- src/gui_2.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/gui_2.py b/src/gui_2.py index 230d7b3a..bcc51b93 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -454,6 +454,8 @@ class App: self._slice_sel_start = -1 self._slice_sel_end = -1 self.context_files = [] + self.ui_synthesis_prompt: str = "" + self.ui_synthesis_selected_takes: dict[str, bool] = {} # --- Rendering & Theme State --- self.perf_show_graphs: dict[str, bool] = {} self.ui_crt_filter = False @@ -3998,8 +4000,8 @@ def render_synthesis_panel(app: App) -> None: """ imgui.text("Select takes to synthesize:") discussions = app.project.get('discussion', {}).get('discussions', {}) - if not hasattr(app, 'ui_synthesis_selected_takes'): app.ui_synthesis_selected_takes = {name: False for name in discussions} - if not hasattr(app, 'ui_synthesis_prompt'): app.ui_synthesis_prompt = "" + if not isinstance(getattr(app, 'ui_synthesis_selected_takes', None), dict): app.ui_synthesis_selected_takes = {name: False for name in discussions} + if not isinstance(getattr(app, 'ui_synthesis_prompt', None), str): app.ui_synthesis_prompt = "" for name in discussions: _, app.ui_synthesis_selected_takes[name] = imgui.checkbox(name, app.ui_synthesis_selected_takes.get(name, False)) imgui.spacing() imgui.text("Synthesis Prompt:") @@ -4134,9 +4136,9 @@ def render_takes_panel(app: App) -> None: imgui.text("Takes & Synthesis") imgui.separator() discussions = app.project.get('discussion', {}).get('discussions', {}) - if not hasattr(app, 'ui_synthesis_selected_takes'): + if not isinstance(getattr(app, 'ui_synthesis_selected_takes', None), dict): app.ui_synthesis_selected_takes = {name: False for name in discussions} - if not hasattr(app, 'ui_synthesis_prompt'): + if not isinstance(getattr(app, 'ui_synthesis_prompt', None), str): app.ui_synthesis_prompt = "" if imgui.begin_table("takes_table", 3, imgui.TableFlags_.resizable | imgui.TableFlags_.borders): imgui.table_setup_column("Name", imgui.TableColumnFlags_.width_stretch)