From 7c713eee6527443a02c1cca8d7b77a368d9ead76 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Mon, 10 Jun 2024 12:00:47 +0500 Subject: [PATCH] nest.remove_task to clean up ownerhistory in more cases 1) It wasn't removing ownerhistory in the case if task was RelatingObject in IfcRelNests 2) Replaced handling of IfcRelNests as an inverse with direct api calls. 3) Added some basic tests. --- .../ifcopenshell/api/sequence/remove_task.py | 28 ++++----- .../test/api/sequence/test_remove_task.py | 59 +++++++++++++++++++ 2 files changed, 71 insertions(+), 16 deletions(-) create mode 100644 src/ifcopenshell-python/test/api/sequence/test_remove_task.py 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