From 301dae103c04c1fa7c51887b95659cdfd63eddcc Mon Sep 17 00:00:00 2001 From: Gorgious56 Date: Tue, 30 Jun 2026 14:06:53 +0200 Subject: [PATCH] Bonsai: guard decorator draws against None and empty lists Three crashes that surfaced when viewport decorators ran against selected non-IFC blender objects or top-level objects with no aggregate parent: - WallAxisDecorator.draw_wall_axis: tool.Ifc.get_entity(obj) returns None for a non-IFC selection (default cube, lamp, camera). The subsequent element.is_a("IfcWall") raised AttributeError on every redraw. Guard with `element and element.is_a(...)`. - _ConnectedNetworkPathDecorator flow-segment loop: same shape; iterates entries that may be None, calls .is_a("IfcFlowSegment") unconditionally. Same guard. - AggregateDecorator.draw_aggregate: indexes aggregates_list[-1] unconditionally in the else branch; raises IndexError when the selected element has no aggregate parent. Also leaves `aggregate` unbound across loop iterations in the `in_aggregate_mode` branch when `index <= 0`. Define `aggregate = None` per loop iteration and guard the [-1] indexing with `elif aggregates_list:`. Generated with the assistance of an AI coding tool. --- src/bonsai/bonsai/bim/module/aggregate/decorator.py | 3 ++- src/bonsai/bonsai/bim/module/model/decorator.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/aggregate/decorator.py b/src/bonsai/bonsai/bim/module/aggregate/decorator.py index f13f189641..987cb6ab8e 100644 --- a/src/bonsai/bonsai/bim/module/aggregate/decorator.py +++ b/src/bonsai/bonsai/bim/module/aggregate/decorator.py @@ -158,12 +158,13 @@ class AggregateDecorator(tool.Blender.ViewportDecorator): aggregates.append(obj) continue + aggregate = None aggregates_list = tool.Aggregate.get_aggregates_recursively(element) if props.in_aggregate_mode and props.editing_aggregate: index = aggregates_list.index(tool.Ifc.get_entity(props.editing_aggregate)) if index > 0: aggregate = aggregates_list[index - 1] - else: + elif aggregates_list: aggregate = aggregates_list[-1] if aggregate: aggregates.append(tool.Ifc.get_object(aggregate)) diff --git a/src/bonsai/bonsai/bim/module/model/decorator.py b/src/bonsai/bonsai/bim/module/model/decorator.py index 65691f6edf..b88f2eb247 100644 --- a/src/bonsai/bonsai/bim/module/model/decorator.py +++ b/src/bonsai/bonsai/bim/module/model/decorator.py @@ -1597,7 +1597,7 @@ class WallAxisDecorator(tool.Blender.ViewportDecorator): self.line_shader.uniform_float("lineWidth", 2.0) for obj in context.selected_objects: element = tool.Ifc.get_entity(obj) - if element.is_a("IfcWall"): + if element and element.is_a("IfcWall"): layers = tool.Model.get_material_layer_parameters(element) axis = tool.Model.get_wall_axis(obj, layers) side = [tuple(list(v) + [obj.location.z]) for v in axis["side"]] @@ -2702,7 +2702,7 @@ class MEPSystemPathDecorator(_ConnectedNetworkPathDecorator): lines: list[tuple[tuple[float, float, float], tuple[float, float, float]]] = [] port_positions: list[tuple[float, float, float]] = [] for element in connected: - if element.is_a("IfcFlowSegment"): + if element and element.is_a("IfcFlowSegment"): if not tool.Geometry.has_axis_representation(element): continue obj = tool.Ifc.get_object(element)