From 5da68721d64b52efd03891ba72164b8349676182 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Mon, 15 Apr 2024 16:54:54 +0500 Subject: [PATCH] document.unassign_document - support batching #4474 --- src/blenderbim/blenderbim/core/document.py | 2 +- src/blenderbim/blenderbim/core/drawing.py | 2 +- src/blenderbim/test/core/test_document.py | 2 +- src/blenderbim/test/core/test_drawing.py | 2 +- .../ifcopenshell/api/__init__.py | 3 ++ .../api/document/unassign_document.py | 51 +++++++++++++------ .../api/document/test_unassign_document.py | 18 ++++--- src/ifcopenshell-python/test/api/test_api.py | 9 ++++ 8 files changed, 64 insertions(+), 25 deletions(-) diff --git a/src/blenderbim/blenderbim/core/document.py b/src/blenderbim/blenderbim/core/document.py index 85cfc00681..ce58e1edf4 100644 --- a/src/blenderbim/blenderbim/core/document.py +++ b/src/blenderbim/blenderbim/core/document.py @@ -113,4 +113,4 @@ def assign_document(ifc, product=None, document=None): def unassign_document(ifc, product=None, document=None): - ifc.run("document.unassign_document", product=product, document=document) + ifc.run("document.unassign_document", products=[product], document=document) diff --git a/src/blenderbim/blenderbim/core/drawing.py b/src/blenderbim/blenderbim/core/drawing.py index 127cbfa7db..cccdc16ad1 100644 --- a/src/blenderbim/blenderbim/core/drawing.py +++ b/src/blenderbim/blenderbim/core/drawing.py @@ -265,7 +265,7 @@ def duplicate_drawing(ifc, drawing_tool, drawing=None, should_duplicate_annotati ifc.run("group.assign_group", group=new_group, products=[new_annotation]) old_reference = drawing_tool.get_drawing_document(new_drawing) - ifc.run("document.unassign_document", product=new_drawing, document=old_reference) + ifc.run("document.unassign_document", products=[new_drawing], document=old_reference) information = ifc.run("document.add_information") uri = drawing_tool.get_default_drawing_path(drawing_name) diff --git a/src/blenderbim/test/core/test_document.py b/src/blenderbim/test/core/test_document.py index 2349870d39..9811c887a8 100644 --- a/src/blenderbim/test/core/test_document.py +++ b/src/blenderbim/test/core/test_document.py @@ -139,5 +139,5 @@ class TestAssignDocument: class TestUnassignDocument: def test_run(self, ifc): - ifc.run("document.unassign_document", product="product", document="document").should_be_called() + ifc.run("document.unassign_document", products=["product"], document="document").should_be_called() subject.unassign_document(ifc, product="product", document="document") diff --git a/src/blenderbim/test/core/test_drawing.py b/src/blenderbim/test/core/test_drawing.py index afe116d072..a2b6608f5d 100644 --- a/src/blenderbim/test/core/test_drawing.py +++ b/src/blenderbim/test/core/test_drawing.py @@ -391,7 +391,7 @@ class TestDuplicateDrawing: ifc.run("group.assign_group", group="new_group", products=["new_annotation"]).should_be_called() drawing.get_drawing_document("new_drawing").should_be_called().will_return("old_reference") - ifc.run("document.unassign_document", product="new_drawing", document="old_reference").should_be_called() + 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") ifc.run("document.add_reference", information="information").should_be_called().will_return("reference") diff --git a/src/ifcopenshell-python/ifcopenshell/api/__init__.py b/src/ifcopenshell-python/ifcopenshell/api/__init__.py index c82e076464..ff0a786292 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/api/__init__.py @@ -102,6 +102,9 @@ ARGUMENTS_DEPRECATION = { "document.assign_document": partial( batching_argument_deprecation, prev_argument="product", new_argument="products" ), + "document.unassign_document": partial( + batching_argument_deprecation, prev_argument="product", new_argument="products" + ), } diff --git a/src/ifcopenshell-python/ifcopenshell/api/document/unassign_document.py b/src/ifcopenshell-python/ifcopenshell/api/document/unassign_document.py index c4fbca8234..dd43573e65 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/document/unassign_document.py +++ b/src/ifcopenshell-python/ifcopenshell/api/document/unassign_document.py @@ -17,16 +17,22 @@ # along with IfcOpenShell. If not, see . import ifcopenshell +import ifcopenshell.api import ifcopenshell.util.element class Usecase: - def __init__(self, file, product=None, document=None): - """Unassigns a document and a product association + def __init__( + self, + file: ifcopenshell.file, + products: list[ifcopenshell.entity_instance], + document: ifcopenshell.entity_instance, + ): + """Unassigns a document and an association to the list of products - :param product: The object that the document reference or information is + :param product: The list of objects that the document reference or information is related to. - :type product: ifcopenshell.entity_instance.entity_instance + :type product: list[ifcopenshell.entity_instance.entity_instance] :param document: The IfcDocumentReference (typically) or in rare cases the IfcDocumentInformation that is associated with the product :type document: ifcopenshell.entity_instance.entity_instance @@ -48,21 +54,36 @@ class Usecase: ifcopenshell.api.run("document.assign_document", model, products=[storey], document=reference) # Now let's change our mind and remove the association - ifcopenshell.api.run("document.unassign_document", model, product=storey, document=reference) + ifcopenshell.api.run("document.unassign_document", model, products=[storey], document=reference) """ self.file = file self.settings = { - "product": product, + "products": products, "document": document, } def execute(self): - for rel in self.settings["product"].HasAssociations: - if rel.is_a("IfcRelAssociatesDocument") and rel.RelatingDocument == self.settings["document"]: - if len(rel.RelatedObjects) == 1: - history = rel.OwnerHistory - self.file.remove(rel) - if history: - ifcopenshell.util.element.remove_deep2(self.file, history) - else: - rel.RelatedObjects = [o for o in rel.RelatedObjects if o != self.settings["product"]] + # TODO: do we need to support non-ifcroot elements like we do in classification.add_reference? + # NOTE: reuses code from `library.un assign_reference` + + reference_rels: set[ifcopenshell.entity_instance] = set() + products = set(self.settings["products"]) + for product in products: + reference_rels.update(product.HasAssociations) + + reference_rels = { + rel + for rel in reference_rels + if rel.is_a("IfcRelAssociatesDocument") and rel.RelatingDocument == self.settings["document"] + } + + for rel in reference_rels: + related_objects = set(rel.RelatedObjects) - products + if related_objects: + rel.RelatedObjects = list(related_objects) + ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": rel}) + else: + history = rel.OwnerHistory + self.file.remove(rel) + if history: + ifcopenshell.util.element.remove_deep2(self.file, history) diff --git a/src/ifcopenshell-python/test/api/document/test_unassign_document.py b/src/ifcopenshell-python/test/api/document/test_unassign_document.py index f58975ce69..bce6c8d6a1 100644 --- a/src/ifcopenshell-python/test/api/document/test_unassign_document.py +++ b/src/ifcopenshell-python/test/api/document/test_unassign_document.py @@ -18,6 +18,7 @@ import test.bootstrap import ifcopenshell.api +import ifcopenshell.util.element class TestUnassignDocument(test.bootstrap.IFC4): @@ -25,16 +26,21 @@ class TestUnassignDocument(test.bootstrap.IFC4): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") reference = ifcopenshell.api.run("document.add_reference", self.file, information=None) ifcopenshell.api.run("document.assign_document", self.file, products=[element], document=reference) - ifcopenshell.api.run("document.unassign_document", self.file, product=element, document=reference) + ifcopenshell.api.run("document.unassign_document", self.file, products=[element], document=reference) assert not element.HasAssociations assert not len(self.file.by_type("IfcRelAssociatesDocument")) def test_unassigning_a_document_used_by_multiple_entities(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element3 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") reference = ifcopenshell.api.run("document.add_reference", self.file, information=None) - ifcopenshell.api.run("document.assign_document", self.file, products=[element], document=reference) - ifcopenshell.api.run("document.assign_document", self.file, products=[element2], document=reference) - ifcopenshell.api.run("document.unassign_document", self.file, product=element, document=reference) - assert not element.HasAssociations - assert element2.HasAssociations[0].RelatingDocument == reference + ifcopenshell.api.run( + "document.assign_document", self.file, products=[element, element2, element3], document=reference + ) + ifcopenshell.api.run("document.unassign_document", self.file, products=[element, element2], document=reference) + assert ifcopenshell.util.element.get_referenced_elements(reference) == {element3} + + +class TestUnassignDocumentIFC2X3(test.bootstrap.IFC2X3, TestUnassignDocument): + pass diff --git a/src/ifcopenshell-python/test/api/test_api.py b/src/ifcopenshell-python/test/api/test_api.py index 66afb798a6..68fe0202c4 100644 --- a/src/ifcopenshell-python/test/api/test_api.py +++ b/src/ifcopenshell-python/test/api/test_api.py @@ -261,3 +261,12 @@ class TestTemporarySupportForDeprecatedAPIArguments(test.bootstrap.IFC4): reference = ifcopenshell.api.run("document.add_reference", self.file, information=None) ifcopenshell.api.run("document.assign_document", self.file, product=element, document=reference) assert element.HasAssociations[0].RelatingDocument == reference + + @deprecation_check + def test_unassigning_a_document(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + reference = ifcopenshell.api.run("document.add_reference", self.file, information=None) + ifcopenshell.api.run("document.assign_document", self.file, products=[element], document=reference) + ifcopenshell.api.run("document.unassign_document", self.file, product=element, document=reference) + assert not element.HasAssociations + assert not len(self.file.by_type("IfcRelAssociatesDocument"))