From 04db09f90a2d2376915d84f7e3a88d17cb083813 Mon Sep 17 00:00:00 2001 From: Petru Conduraru Date: Sun, 12 Jul 2026 18:42:18 +0300 Subject: [PATCH] Bonsai: fix DirectProfileEdit crash exiting edit mode (#7624) Exiting a slab DirectProfileEdit raised `AttributeError: 'OverrideModeSetObject' object has no attribute 'edited_objs'`. DirectProfileEdit's fallback paths called bpy.ops.bim.override_mode_set_object() bare, which runs in EXEC context and dispatches straight to the operator's _execute(); but edited_objs / unchanged_objs_with_openings are only initialised in _invoke(), so _execute iterated a never-set attribute and crashed. Every other call site of this operator already passes "INVOKE_DEFAULT"; only DirectProfileEdit's four fallbacks missed it. Pass "INVOKE_DEFAULT" at all four sites so _invoke runs first, matching the rest of the codebase. Verified: the bare-call path reproduces the exact AttributeError; the invoke path initialises edited_objs before execute() runs and completes cleanly. All override_mode_set_object call sites in the file now consistently use INVOKE_DEFAULT; the operators still register, and core test_geometry.py passes (14). Generated with the assistance of an AI coding tool. Co-Authored-By: Claude Opus 4.8 --- src/bonsai/bonsai/bim/module/geometry/operator.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/geometry/operator.py b/src/bonsai/bonsai/bim/module/geometry/operator.py index 9bc0566532..37951f145e 100644 --- a/src/bonsai/bonsai/bim/module/geometry/operator.py +++ b/src/bonsai/bonsai/bim/module/geometry/operator.py @@ -2814,7 +2814,7 @@ class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): return self.exit_element_edit_mode(context, obj, element) # For other edit modes, use standard operator - return bpy.ops.bim.override_mode_set_object() + return bpy.ops.bim.override_mode_set_object("INVOKE_DEFAULT") def exit_item_edit_mode(self, context, obj): """Exit from representation item editing.""" @@ -2825,7 +2825,7 @@ class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): item = tool.Geometry.get_active_representation(obj) if not item: - return bpy.ops.bim.override_mode_set_object() + return bpy.ops.bim.override_mode_set_object("INVOKE_DEFAULT") # Fix vertex order for annotation items props = tool.Geometry.get_geometry_props() @@ -2939,7 +2939,7 @@ class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): # Fallback else: - return bpy.ops.bim.override_mode_set_object() + return bpy.ops.bim.override_mode_set_object("INVOKE_DEFAULT") except Exception as e: self.report({"ERROR"}, f"Failed to save item changes: {str(e)}") @@ -2966,7 +2966,7 @@ class DirectProfileEdit(bpy.types.Operator, tool.Ifc.Operator): return {"CANCELLED"} # Fallback to standard operator - return bpy.ops.bim.override_mode_set_object() + return bpy.ops.bim.override_mode_set_object("INVOKE_DEFAULT") def handle_enter_edit_mode(self, context): """Handle entering edit mode from object mode."""