diff --git a/src/ifcopenshell-python/ifcopenshell/api/pset/unshare_pset.py b/src/ifcopenshell-python/ifcopenshell/api/pset/unshare_pset.py index a1c29046ea..c88f74f857 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/pset/unshare_pset.py +++ b/src/ifcopenshell-python/ifcopenshell/api/pset/unshare_pset.py @@ -57,6 +57,22 @@ def unshare_pset( assert new_pset != pset assert ifcopenshell.util.element.get_elements_by_pset(new_pset) == {element2} """ + + if not products: + raise Exception("No products provided.") + + # If pset has no other elements besides the provided products, + # then we skip the first product, so it won't get additional pset copy + # leaving the original pset orphaned. + pset_elements = ifcopenshell.util.element.get_elements_by_pset(pset) + products_original = products + + if set(products) == pset_elements: + products = products[1:] + + if not products: + raise Exception(f"Provided product is the only element to which pset is assigned: {products_original[0]}.") + products_occurrences: set[ifcopenshell.entity_instance] = set() products_types: set[ifcopenshell.entity_instance] = set() for product in products: diff --git a/src/ifcopenshell-python/test/api/pset/test_unshare_pset.py b/src/ifcopenshell-python/test/api/pset/test_unshare_pset.py index 3d3e75afe9..b13bd5196e 100644 --- a/src/ifcopenshell-python/test/api/pset/test_unshare_pset.py +++ b/src/ifcopenshell-python/test/api/pset/test_unshare_pset.py @@ -69,6 +69,32 @@ class TestUnsharePset(test.bootstrap.IFC4): assert used_psets == set(psets) + def test_unshare_pset_for_all_pset_elements(self): + elements = [self.file.create_entity("IfcWall") for _ in range(3)] + + pset = ifcopenshell.api.pset.add_pset(self.file, elements[0], "Foo") + pset_id = pset.id() + rel = self.file.by_type("IfcRelDefinesByProperties")[0] + rel.RelatedObjects = elements + + new_psets = ifcopenshell.api.pset.unshare_pset(self.file, elements, pset) + # Original pset still exists and it's not orphaned. + pset = self.file.by_id(pset_id) + + assert isinstance(new_psets, list) + assert len(new_psets) == 2 + + assert len(psets := self.file.by_type("IfcPropertySet")) == 3 + assert len(self.file.by_type("IfcRelDefinesByProperties")) == 3 + + used_elements = set() + for pset in psets: + pset_elements = ifcopenshell.util.element.get_elements_by_pset(pset) + assert len(pset_elements) == 1 + used_elements.update(pset_elements) + + assert used_elements == set(elements) + class TestUnsharePsetIFC2X3(test.bootstrap.IFC2X3, TestUnsharePset): pass diff --git a/src/ifcpatch/ifcpatch/recipes/UnsharePsets.py b/src/ifcpatch/ifcpatch/recipes/UnsharePsets.py index 3769008971..7020a86504 100644 --- a/src/ifcpatch/ifcpatch/recipes/UnsharePsets.py +++ b/src/ifcpatch/ifcpatch/recipes/UnsharePsets.py @@ -21,7 +21,6 @@ import ifcopenshell.api.pset import ifcopenshell.guid import ifcopenshell.util.element import ifcopenshell.util.selector -from typing import Union from logging import Logger @@ -79,7 +78,7 @@ class Patcher: new_psets = [] for pset, elements in psets.items(): # Let the first element to keep the original property set. - elements = list(elements)[1:] + elements = list(elements) new_psets.extend(ifcopenshell.api.pset.unshare_pset(self.file, elements, pset)) print(f"{len(new_psets)} new psets were created.")