diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_task.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_task.py index 6f388c7921..42b57a364c 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_task.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_task.py @@ -18,6 +18,7 @@ import ifcopenshell import ifcopenshell.api +import ifcopenshell.api.nest import ifcopenshell.util.element @@ -64,28 +65,23 @@ def remove_task(file: ifcopenshell.file, task: ifcopenshell.entity_instance) -> ) if settings["task"].TaskTime: file.remove(settings["task"].TaskTime) + + # Handle IfcRelNests. + if rels := settings["task"].IsNestedBy: + subtasks = rels[0].RelatedObjects + # Use batching for optimization. + ifcopenshell.api.nest.unassign_object(file, subtasks) + for task_ in subtasks: + ifcopenshell.api.run("sequence.remove_task", file, task=task_) + if settings["task"].Nests: + ifcopenshell.api.nest.unassign_object(file, [settings["task"]]) + for inverse in file.get_inverse(settings["task"]): if inverse.is_a("IfcRelSequence"): history = inverse.OwnerHistory file.remove(inverse) if history: ifcopenshell.util.element.remove_deep2(file, history) - elif inverse.is_a("IfcRelNests"): - if inverse.RelatingObject == settings["task"]: - for related_object in inverse.RelatedObjects: - ifcopenshell.api.run("sequence.remove_task", file, task=related_object) - elif not inverse.RelatedObjects: - history = inverse.OwnerHistory - file.remove(inverse) - if history: - ifcopenshell.util.element.remove_deep2(file, history) - elif settings["task"] in inverse.RelatedObjects: - related_objects = list(inverse.RelatedObjects) - related_objects.remove(settings["task"]) - if not related_objects: - file.remove(inverse) - else: - inverse.RelatedObjects = related_objects elif inverse.is_a("IfcRelAssignsToControl"): if inverse.RelatingControl == settings["task"] or len(inverse.RelatedObjects) == 1: history = inverse.OwnerHistory diff --git a/src/ifcopenshell-python/test/api/sequence/test_remove_task.py b/src/ifcopenshell-python/test/api/sequence/test_remove_task.py new file mode 100644 index 0000000000..ed6c5822e3 --- /dev/null +++ b/src/ifcopenshell-python/test/api/sequence/test_remove_task.py @@ -0,0 +1,59 @@ +# IfcOpenShell - IFC toolkit and geometry engine +# Copyright (C) 2021 Dion Moult +# +# This file is part of IfcOpenShell. +# +# IfcOpenShell is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# IfcOpenShell is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with IfcOpenShell. If not, see . + +import pytest +import test.bootstrap +import ifcopenshell.api +import ifcopenshell.api.nest +import ifcopenshell.api.sequence + + +# NOTE: sequence module features relies on entities introduced in IFC4 +# therefore no IFC2X3 tests +class TestRemoveTask(test.bootstrap.IFC4): + def test_remove_task(self): + self.file.create_entity("IfcProject") + work_schedule = ifcopenshell.api.sequence.add_work_schedule(self.file) + task = ifcopenshell.api.sequence.add_task(self.file, work_schedule=work_schedule) + ifcopenshell.api.sequence.remove_task(self.file, task) + assert len(self.file.by_type("IfcTask")) == 0 + + def test_remove_task_with_subtasks(self): + self.file.create_entity("IfcProject") + work_schedule = ifcopenshell.api.sequence.add_work_schedule(self.file) + task = ifcopenshell.api.sequence.add_task(self.file, work_schedule=work_schedule) + subtask1 = ifcopenshell.api.sequence.add_task(self.file, work_schedule=work_schedule) + subtask2 = ifcopenshell.api.sequence.add_task(self.file, work_schedule=work_schedule) + ifcopenshell.api.nest.assign_object(self.file, related_objects=[subtask1, subtask2], relating_object=task) + ifcopenshell.api.sequence.remove_task(self.file, task) + assert len(self.file.by_type("IfcTask")) == 0 + assert len(self.file.by_type("IfcRelNests")) == 0 + + def test_remove_subtask(self): + self.file.create_entity("IfcProject") + work_schedule = ifcopenshell.api.sequence.add_work_schedule(self.file) + task = ifcopenshell.api.sequence.add_task(self.file, work_schedule=work_schedule) + subtask1 = ifcopenshell.api.sequence.add_task(self.file, work_schedule=work_schedule) + ifcopenshell.api.nest.assign_object(self.file, related_objects=[subtask1], relating_object=task) + ifcopenshell.api.sequence.remove_task(self.file, subtask1) + assert len(self.file.by_type("IfcTask")) == 1 + assert len(self.file.by_type("IfcRelNests")) == 0 + + +class TestRemoveTaskIFC4X3(test.bootstrap.IFC4X3, TestRemoveTask): + pass