diff --git a/src/bonsai/bonsai/bim/module/model/preview_base.py b/src/bonsai/bonsai/bim/module/model/preview_base.py index b58e6ea246..13cde4e68a 100644 --- a/src/bonsai/bonsai/bim/module/model/preview_base.py +++ b/src/bonsai/bonsai/bim/module/model/preview_base.py @@ -60,8 +60,12 @@ def get_preview_props(context: bpy.types.Context, attr: str): Returns ``None`` if the umbrella isn't attached yet — true briefly during addon register and during plug-out, so polls / draw callbacks must defend against ``None`` rather than assuming the prop is always - available.""" - preview = getattr(context.scene, "BIMPreviewProperties", None) + available. Also tolerates contexts without a ``scene`` attribute + (test mocks built from ``SimpleNamespace``).""" + scene = getattr(context, "scene", None) + if scene is None: + return None + preview = getattr(scene, "BIMPreviewProperties", None) return getattr(preview, attr, None) if preview is not None else None diff --git a/src/bonsai/bonsai/bim/module/project/operator.py b/src/bonsai/bonsai/bim/module/project/operator.py index 284d427cf3..db6b6389ee 100644 --- a/src/bonsai/bonsai/bim/module/project/operator.py +++ b/src/bonsai/bonsai/bim/module/project/operator.py @@ -63,6 +63,7 @@ import bonsai.core.project as core import bonsai.tool as tool from bonsai.bim import export_ifc, import_ifc from bonsai.bim.ifc import IfcStore +from bonsai.bim.module.model import preview_base from bonsai.bim.module.model.decorator import FaceAreaDecorator, PolylineDecorator from bonsai.bim.module.model.polyline import PolylineOperator from bonsai.bim.module.project.data import LinksData, ProjectLibraryData @@ -1936,6 +1937,10 @@ class ExportIFC(bpy.types.Operator, ExportHelper): def _execute(self, context): committed, failed_commits = tool.Parametric.commit_pending_edits() + # Previews are session-transient — discard rather than commit. Sibling + # gizmo polls gate on each preview's is_active flag, and a stuck flag + # persisted through the save would silently hide them on reload. + preview_base.discard_pending_previews(context.scene) # Suffix is appended to the IFC save-success report below so the auto-commit # info isn't immediately overwritten by the success message in Blender's # status bar (only the latest self.report({"INFO"}, ...) sticks). diff --git a/src/bonsai/test/bim/module/model/test_wall_header_refresh.py b/src/bonsai/test/bim/module/model/test_wall_header_refresh.py index 933fab2454..41b8719ec5 100644 --- a/src/bonsai/test/bim/module/model/test_wall_header_refresh.py +++ b/src/bonsai/test/bim/module/model/test_wall_header_refresh.py @@ -75,7 +75,7 @@ def test_geom_generation_invalidates_wall_geom_cache(): sentinel_a = {"length": 1.0, "height": 2.0, "x_angle": 0.0} sentinel_b = {"length": 1.5, "height": 2.5, "x_angle": 0.0} - with patch.object(wall_mod, "_read_wall_geometry", side_effect=[sentinel_a, sentinel_b]): + with patch.object(tool.Wall, "read_geometry", side_effect=[sentinel_a, sentinel_b]): first = wall_mod._get_wall_geom_cached(group, fake_obj) assert first is sentinel_a # Same call without a generation bump must hit the cache (no extra read).