From f3efb1601a4222b75b0ebe36795db5968cb431f8 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Thu, 24 Jul 2025 12:05:01 +0500 Subject: [PATCH] copy_cost_schedule - add a test --- .../ifcopenshell/util/cost.py | 4 +- .../test/api/cost/test_copy_cost_schedule.py | 48 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/ifcopenshell-python/test/api/cost/test_copy_cost_schedule.py diff --git a/src/ifcopenshell-python/ifcopenshell/util/cost.py b/src/ifcopenshell-python/ifcopenshell/util/cost.py index 2b6f425fce..d778603310 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/cost.py +++ b/src/ifcopenshell-python/ifcopenshell/util/cost.py @@ -22,6 +22,7 @@ from typing import Optional, Union, Literal, Any from collections.abc import Generator import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper import ifcopenshell.util.attribute +import ifcopenshell.util.element from ifcopenshell.util.doc import get_predefined_type_doc from ifcopenshell.util.element import get_psets from ifcopenshell.util.unit import get_unit_symbol @@ -211,12 +212,13 @@ def get_nested_cost_items(cost_item: ifcopenshell.entity_instance, is_deep=False if is_deep: return list(get_all_nested_cost_items(cost_item)) else: - return [obj for rel in cost_item.IsNestedBy for obj in rel.RelatedObjects] + return ifcopenshell.util.element.get_components(cost_item) def get_schedule_cost_items( cost_schedule: ifcopenshell.entity_instance, ) -> Generator[ifcopenshell.entity_instance, None, None]: + """Get all cost schedule cost items, including the nested ones.""" for cost_item in get_root_cost_items(cost_schedule): yield cost_item yield from get_all_nested_cost_items(cost_item) diff --git a/src/ifcopenshell-python/test/api/cost/test_copy_cost_schedule.py b/src/ifcopenshell-python/test/api/cost/test_copy_cost_schedule.py new file mode 100644 index 0000000000..489d0e03b5 --- /dev/null +++ b/src/ifcopenshell-python/test/api/cost/test_copy_cost_schedule.py @@ -0,0 +1,48 @@ +# IfcOpenShell - IFC toolkit and geometry engine +# Copyright (C) 2024 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 ifcopenshell.api.cost +import ifcopenshell.util.cost +import test.bootstrap + + +class TestCopyCostSchedule(test.bootstrap.IFC4): + def test_run(self): + schedule = ifcopenshell.api.cost.add_cost_schedule(self.file, name="Foo") + item = ifcopenshell.api.cost.add_cost_item(self.file, cost_schedule=schedule) + ifcopenshell.api.cost.add_cost_item(self.file, cost_item=item) # Subitem. + old_cost_items = set(self.file.by_type("IfcCostItem")) + + new_schedule = ifcopenshell.api.cost.copy_cost_schedule(self.file, schedule) + + # We don't check how well IfcCostItems are copied, + # it should be tested separately in test_copy_cost_item. + assert isinstance(new_schedule, ifcopenshell.entity_instance) + assert new_schedule != schedule + assert len(ifcopenshell.util.cost.get_root_cost_items(new_schedule)) == 1 + new_cost_items = set(ifcopenshell.util.cost.get_schedule_cost_items(new_schedule)) + assert len(new_cost_items) == 2 + assert len(new_cost_items.intersection(old_cost_items)) == 0 + + +class TestCopyCostScheduleIFC2X3(test.bootstrap.IFC2X3, TestCopyCostSchedule): + pass + + +class TestCopyCostScheduleIFC4X3(test.bootstrap.IFC4X3, TestCopyCostSchedule): + pass