From a60e03e32a77de6437f8d8b83886a4e7859bbf21 Mon Sep 17 00:00:00 2001 From: Petru Conduraru Date: Mon, 20 Jul 2026 19:55:22 +0300 Subject: [PATCH] bonsai: add regression coverage for foreign representation-item ids (#7351) Duplicating an object whose mesh data still carries an ifc_definition_id from a different IFC session (e.g. pasted in via Blender's copy/paste or a cross-file diff workflow) used to crash duplicate_ifc_objects with RuntimeError: Instance #N not found, raised from an unguarded by_id call in Geometry.get_representation_item. That call is already wrapped in try/except RuntimeError on v0.8.0 HEAD (landed incidentally in 36372627db, "Fix validate_type corruption; remove debug prints"), so the crash from #7351 no longer reproduces. This adds explicit test coverage for that guard: a foreign/missing id resolves to None instead of raising, a real in-file representation item still resolves normally, and a real in-file id that is not a representation item still returns None. Generated with the assistance of an AI coding tool. --- src/bonsai/test/tool/test_geometry.py | 39 +++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/bonsai/test/tool/test_geometry.py b/src/bonsai/test/tool/test_geometry.py index 5683ce03de..a7a3511eb1 100644 --- a/src/bonsai/test/tool/test_geometry.py +++ b/src/bonsai/test/tool/test_geometry.py @@ -135,6 +135,45 @@ class TestGetRepresentationData(NewFile): assert subject.get_representation_data(representation) == data +class TestGetRepresentationItem(NewFile): + def test_returns_the_item_for_a_live_representation_item_id(self): + ifc = ifcopenshell.file() + tool.Ifc.set(ifc) + item = ifc.createIfcExtrudedAreaSolid() + data = bpy.data.meshes.new("Mesh") + subject.get_mesh_props(data).ifc_definition_id = item.id() + obj = bpy.data.objects.new("Object", data) + assert subject.get_representation_item(obj) == item + assert subject.is_representation_item(obj) is True + + def test_returns_none_for_a_live_id_that_is_not_a_representation_item(self): + ifc = ifcopenshell.file() + tool.Ifc.set(ifc) + wall = ifcopenshell.api.root.create_entity(ifc, ifc_class="IfcWall") + data = bpy.data.meshes.new("Mesh") + subject.get_mesh_props(data).ifc_definition_id = wall.id() + obj = bpy.data.objects.new("Object", data) + assert subject.get_representation_item(obj) is None + assert subject.is_representation_item(obj) is False + + def test_returns_none_instead_of_raising_for_an_id_from_a_different_file(self): + # Regression test for #7351: an object duplicated/pasted in from a + # different IFC session can keep an ifc_definition_id that only + # existed in that other file. Against the current file that id is + # simply missing, and this must be treated as "not a representation + # item of this file" rather than crash with `by_id`'s RuntimeError. + other_ifc = ifcopenshell.file() + foreign_item = other_ifc.createIfcExtrudedAreaSolid() + + ifc = ifcopenshell.file() + tool.Ifc.set(ifc) + data = bpy.data.meshes.new("Mesh") + subject.get_mesh_props(data).ifc_definition_id = foreign_item.id() + obj = bpy.data.objects.new("Object", data) + assert subject.get_representation_item(obj) is None + assert subject.is_representation_item(obj) is False + + class TestGetActiveRepresentation(NewFile): def test_returns_representation_for_live_id(self): ifc = ifcopenshell.file()