From 3a8619726b9867871485b7b1f5fe44b0e5d8b0d4 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Tue, 14 Jul 2026 19:57:27 +0500 Subject: [PATCH] core.drawing: deduplicate code, fix test Core test was trying to access actual ifc data (`ifc.get().by_type("IfcGroup")` and was failing. --- src/bonsai/bonsai/core/drawing.py | 52 +++------------------------- src/bonsai/bonsai/core/tool.py | 2 ++ src/bonsai/bonsai/tool/drawing.py | 27 +++++++++++++++ src/bonsai/test/core/test_drawing.py | 14 ++++++-- 4 files changed, 45 insertions(+), 50 deletions(-) diff --git a/src/bonsai/bonsai/core/drawing.py b/src/bonsai/bonsai/core/drawing.py index ed37fcb3b7..5192aeaa37 100644 --- a/src/bonsai/bonsai/core/drawing.py +++ b/src/bonsai/bonsai/core/drawing.py @@ -303,17 +303,7 @@ def add_drawing( ifc_representation_class=None, ) - drawings_parent_group = None - for group in ifc.get().by_type("IfcGroup"): - if group.Name == "DRAWINGS" and group.ObjectType == "DRAWINGS": - drawings_parent_group = group - break - - if not drawings_parent_group: - drawings_parent_group = ifc.run("group.add_group") - ifc.run( - "group.edit_group", group=drawings_parent_group, attributes={"Name": "DRAWINGS", "ObjectType": "DRAWINGS"} - ) + drawings_parent_group = drawing.ensure_drawings_parent_group() group = ifc.run("group.add_group") ifc.run("group.edit_group", group=group, attributes={"Name": drawing_name, "ObjectType": "DRAWING"}) @@ -352,19 +342,7 @@ def add_drawing( ) drawing.setup_shading_styles_path(shading_styles_path) - drawings_parent_document = None - for document in ifc.get().by_type("IfcDocumentInformation"): - if document.Name == "DRAWINGS" and document.Scope == "DRAWINGS": - drawings_parent_document = document - break - - if not drawings_parent_document: - drawings_parent_document = ifc.run("document.add_information") - if ifc.get_schema() == "IFC2X3": - attributes = {"DocumentId": "DRAWINGS", "Name": "DRAWINGS", "Scope": "DRAWINGS"} - else: - attributes = {"Identification": "DRAWINGS", "Name": "DRAWINGS", "Scope": "DRAWINGS"} - ifc.run("document.edit_information", information=drawings_parent_document, attributes=attributes) + drawings_parent_document = drawing.ensure_drawings_parent_document() information = ifc.run("document.add_information", parent=drawings_parent_document) uri = drawing.get_default_drawing_path(drawing_name) @@ -395,17 +373,7 @@ def duplicate_drawing( group = drawing_tool.get_drawing_group(new_drawing) ifc.run("group.unassign_group", group=group, products=[new_drawing]) - drawings_parent_group = None - for parent_group in ifc.get().by_type("IfcGroup"): - if parent_group.Name == "DRAWINGS" and parent_group.ObjectType == "DRAWINGS": - drawings_parent_group = parent_group - break - - if not drawings_parent_group: - drawings_parent_group = ifc.run("group.add_group") - ifc.run( - "group.edit_group", group=drawings_parent_group, attributes={"Name": "DRAWINGS", "ObjectType": "DRAWINGS"} - ) + drawings_parent_group = drawing_tool.ensure_drawings_parent_group() new_group = ifc.run("group.add_group") ifc.run("group.edit_group", group=new_group, attributes={"Name": drawing_name, "ObjectType": "DRAWING"}) @@ -426,19 +394,7 @@ def duplicate_drawing( old_reference = drawing_tool.get_drawing_document(new_drawing) ifc.run("document.unassign_document", products=[new_drawing], document=old_reference) - drawings_parent_document = None - for document in ifc.get().by_type("IfcDocumentInformation"): - if document.Name == "DRAWINGS" and document.Scope == "DRAWINGS": - drawings_parent_document = document - break - - if not drawings_parent_document: - drawings_parent_document = ifc.run("document.add_information") - if ifc.get_schema() == "IFC2X3": - attributes = {"DocumentId": "DRAWINGS", "Name": "DRAWINGS", "Scope": "DRAWINGS"} - else: - attributes = {"Identification": "DRAWINGS", "Name": "DRAWINGS", "Scope": "DRAWINGS"} - ifc.run("document.edit_information", information=drawings_parent_document, attributes=attributes) + drawings_parent_document = drawing_tool.ensure_drawings_parent_document() information = ifc.run("document.add_information", parent=drawings_parent_document) uri = drawing_tool.get_default_drawing_path(drawing_name) diff --git a/src/bonsai/bonsai/core/tool.py b/src/bonsai/bonsai/core/tool.py index d5c887ce23..534cd511a4 100644 --- a/src/bonsai/bonsai/core/tool.py +++ b/src/bonsai/bonsai/core/tool.py @@ -354,6 +354,8 @@ class Drawing: def enable_editing_schedules(cls): pass def enable_editing_sheets(cls): pass def enable_editing_text(cls, obj): pass + def ensure_drawings_parent_document(cls): pass + def ensure_drawings_parent_group(cls): pass def ensure_unique_drawing_name(cls, name): pass def ensure_unique_identification(cls, identification): pass def export_font_size(cls, obj): pass diff --git a/src/bonsai/bonsai/tool/drawing.py b/src/bonsai/bonsai/tool/drawing.py index c43aa9e73e..b6d68dbc6a 100644 --- a/src/bonsai/bonsai/tool/drawing.py +++ b/src/bonsai/bonsai/tool/drawing.py @@ -38,6 +38,7 @@ import ifcopenshell.api.context import ifcopenshell.api.document import ifcopenshell.api.drawing import ifcopenshell.api.geometry +import ifcopenshell.api.group import ifcopenshell.api.pset import ifcopenshell.api.root import ifcopenshell.geom @@ -773,6 +774,32 @@ class Drawing(bonsai.core.tool.Drawing): def get_drawing_target_view(cls, drawing: ifcopenshell.entity_instance) -> str: return ifcopenshell.util.element.get_psets(drawing).get("EPset_Drawing", {}).get("TargetView", "MODEL_VIEW") + @classmethod + def ensure_drawings_parent_document(cls) -> ifcopenshell.entity_instance: + ifc_file = tool.Ifc.get() + for document in ifc_file.by_type("IfcDocumentInformation"): + if document.Name == "DRAWINGS" and document.Scope == "DRAWINGS": + return document + document = ifcopenshell.api.document.add_information(ifc_file) + if ifc_file.schema == "IFC2X3": + attributes = {"DocumentId": "DRAWINGS", "Name": "DRAWINGS", "Scope": "DRAWINGS"} + else: + attributes = {"Identification": "DRAWINGS", "Name": "DRAWINGS", "Scope": "DRAWINGS"} + ifcopenshell.api.document.edit_information(ifc_file, information=document, attributes=attributes) + return document + + @classmethod + def ensure_drawings_parent_group(cls) -> ifcopenshell.entity_instance: + ifc_file = tool.Ifc.get() + for group in ifc_file.by_type("IfcGroup"): + if group.Name == "DRAWINGS" and group.ObjectType == "DRAWINGS": + return group + group = ifcopenshell.api.group.add_group(ifc_file) + ifcopenshell.api.group.edit_group( + ifc_file, group=group, attributes={"Name": "DRAWINGS", "ObjectType": "DRAWINGS"} + ) + return group + @classmethod def get_group_elements(cls, group: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]: for rel in group.IsGroupedBy or []: diff --git a/src/bonsai/test/core/test_drawing.py b/src/bonsai/test/core/test_drawing.py index 52822aa754..439597056f 100644 --- a/src/bonsai/test/core/test_drawing.py +++ b/src/bonsai/test/core/test_drawing.py @@ -347,11 +347,13 @@ class TestAddDrawing: context="context", ifc_representation_class=None, ).should_be_called().will_return("element") + drawing.ensure_drawings_parent_group().should_be_called().will_return("drawings_parent_group") ifc.run("group.add_group").should_be_called().will_return("group") ifc.run( "group.edit_group", group="group", attributes={"Name": "name", "ObjectType": "DRAWING"} ).should_be_called() ifc.run("group.assign_group", group="group", products=["element"]).should_be_called() + ifc.run("group.assign_group", group="drawings_parent_group", products=["group"]).should_be_called() collector.assign("obj").should_be_called() ifc.run("pset.add_pset", product="element", name="EPset_Drawing").should_be_called().will_return("pset") drawing.get_default_drawing_resource_path("Stylesheet").should_be_called().will_return("stylesheet.css") @@ -381,8 +383,11 @@ class TestAddDrawing: "CurrentShadingStyle": "Blender Default", }, ).should_be_called() + drawing.ensure_drawings_parent_document().should_be_called().will_return("drawings_parent_document") drawing.get_default_drawing_path("name").should_be_called().will_return("uri") - ifc.run("document.add_information").should_be_called().will_return("information") + ifc.run("document.add_information", parent="drawings_parent_document").should_be_called().will_return( + "information" + ) ifc.run("document.add_reference", information="information").should_be_called().will_return("reference") ifc.get_schema().should_be_called().will_return("IFC4") ifc.run( @@ -406,11 +411,13 @@ class TestDuplicateDrawing: drawing.set_name("new_drawing", "unique_name").should_be_called() drawing.get_drawing_group("new_drawing").should_be_called().will_return("group") ifc.run("group.unassign_group", group="group", products=["new_drawing"]).should_be_called() + drawing.ensure_drawings_parent_group().should_be_called().will_return("drawings_parent_group") ifc.run("group.add_group").should_be_called().will_return("new_group") ifc.run( "group.edit_group", group="new_group", attributes={"Name": "unique_name", "ObjectType": "DRAWING"} ).should_be_called() ifc.run("group.assign_group", group="new_group", products=["new_drawing"]).should_be_called() + ifc.run("group.assign_group", group="drawings_parent_group", products=["new_group"]).should_be_called() drawing.get_group_elements("group").should_be_called().will_return(["drawing", "annotation"]) ifc.get_object("annotation").should_be_called().will_return("annotation_obj") geometry.duplicate_ifc_objects(["annotation_obj"]).should_be_called().will_return( @@ -425,7 +432,10 @@ class TestDuplicateDrawing: drawing.get_drawing_document("new_drawing").should_be_called().will_return("old_reference") ifc.run("document.unassign_document", products=["new_drawing"], document="old_reference").should_be_called() - ifc.run("document.add_information").should_be_called().will_return("information") + drawing.ensure_drawings_parent_document().should_be_called().will_return("drawings_parent_document") + ifc.run("document.add_information", parent="drawings_parent_document").should_be_called().will_return( + "information" + ) ifc.run("document.add_reference", information="information").should_be_called().will_return("reference") ifc.get_schema().should_be_called().will_return("IFC4") drawing.get_default_drawing_path("unique_name").should_be_called().will_return("drawing_path")