From da838a2c7cfcc3a75bdf59b40452daf1a05bc281 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Tue, 9 Apr 2024 16:06:21 +0500 Subject: [PATCH] deprecate spatial.remove_container in favor of spatial.assign_container added temporary support for old version with warnings: WARNING. `spatial.remove_container` api method is deprecated and should be replaced with spatial.unassign_container WARNING. `product` argument is deprecated for API method "spatial.remove_container" and should be replaced with `products`. --- src/blenderbim/blenderbim/core/spatial.py | 2 +- src/blenderbim/test/core/test_spatial.py | 2 +- .../ifcopenshell/api/__init__.py | 21 ++++- .../api/spatial/remove_container.py | 77 ------------------- .../test/api/spatial/test_remove_container.py | 54 ------------- .../api/spatial/test_unassign_container.py | 16 +++- src/ifcopenshell-python/test/api/test_api.py | 7 ++ 7 files changed, 40 insertions(+), 139 deletions(-) delete mode 100644 src/ifcopenshell-python/ifcopenshell/api/spatial/remove_container.py delete mode 100644 src/ifcopenshell-python/test/api/spatial/test_remove_container.py diff --git a/src/blenderbim/blenderbim/core/spatial.py b/src/blenderbim/blenderbim/core/spatial.py index c4cd3f042d..d7e8c24e7d 100644 --- a/src/blenderbim/blenderbim/core/spatial.py +++ b/src/blenderbim/blenderbim/core/spatial.py @@ -78,7 +78,7 @@ def change_spatial_level(spatial, parent=None): def remove_container(ifc, collector, obj=None): - ifc.run("spatial.remove_container", product=ifc.get_entity(obj)) + ifc.run("spatial.unassign_container", products=[ifc.get_entity(obj)]) collector.assign(obj) diff --git a/src/blenderbim/test/core/test_spatial.py b/src/blenderbim/test/core/test_spatial.py index dda55aed94..b77e95dc59 100644 --- a/src/blenderbim/test/core/test_spatial.py +++ b/src/blenderbim/test/core/test_spatial.py @@ -72,7 +72,7 @@ class TestChangeSpatialLevel: class TestRemoveContainer: def test_run(self, ifc, collector): ifc.get_entity("obj").should_be_called().will_return("element") - ifc.run("spatial.remove_container", product="element").should_be_called() + ifc.run("spatial.unassign_container", products=["element"]).should_be_called() collector.assign("obj").should_be_called() subject.remove_container(ifc, collector, obj="obj") diff --git a/src/ifcopenshell-python/ifcopenshell/api/__init__.py b/src/ifcopenshell-python/ifcopenshell/api/__init__.py index 192caa6cad..a77df87537 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/__init__.py +++ b/src/ifcopenshell-python/ifcopenshell/api/__init__.py @@ -31,7 +31,12 @@ pre_listeners = {} post_listeners = {} -def batching_argument_deprecation(usecase_path: str, settings: dict, prev_argument: str, new_argument: str) -> dict: +def batching_argument_deprecation( + usecase_path: str, settings: dict, prev_argument: str, new_argument: str, replace_usecase: Optional[str] = None +) -> tuple[str, dict]: + if replace_usecase is not None: + print(f"WARNING. `{usecase_path}` api method is deprecated and should be replaced with `{replace_usecase}`.") + if prev_argument in settings: print( f"WARNING. `{prev_argument}` argument is deprecated for API method " @@ -39,7 +44,7 @@ def batching_argument_deprecation(usecase_path: str, settings: dict, prev_argume ) settings = settings | {new_argument: [settings[prev_argument]]} settings.pop(prev_argument) - return settings + return (replace_usecase or usecase_path, settings) ARGUMENTS_DEPRECATION = { @@ -51,9 +56,17 @@ ARGUMENTS_DEPRECATION = { ), "group.unassign_group": partial(batching_argument_deprecation, prev_argument="product", new_argument="products"), "aggregate.assign_object": partial(batching_argument_deprecation, prev_argument="product", new_argument="products"), - "aggregate.unassign_object": partial(batching_argument_deprecation, prev_argument="product", new_argument="products"), + "aggregate.unassign_object": partial( + batching_argument_deprecation, prev_argument="product", new_argument="products" + ), "layer.assign_layer": partial(batching_argument_deprecation, prev_argument="item", new_argument="items"), "layer.unassign_layer": partial(batching_argument_deprecation, prev_argument="item", new_argument="items"), + "spatial.remove_container": partial( + batching_argument_deprecation, + prev_argument="product", + new_argument="products", + replace_usecase="spatial.unassign_container", + ), } @@ -69,7 +82,7 @@ def run( # see #4531 if usecase_path in ARGUMENTS_DEPRECATION: - settings = ARGUMENTS_DEPRECATION[usecase_path](usecase_path, settings) + usecase_path, settings = ARGUMENTS_DEPRECATION[usecase_path](usecase_path, settings) # TODO: settings serialization for client-server systems # def serialise_entity_instance(entity): diff --git a/src/ifcopenshell-python/ifcopenshell/api/spatial/remove_container.py b/src/ifcopenshell-python/ifcopenshell/api/spatial/remove_container.py deleted file mode 100644 index c2c083bd06..0000000000 --- a/src/ifcopenshell-python/ifcopenshell/api/spatial/remove_container.py +++ /dev/null @@ -1,77 +0,0 @@ -# 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 ifcopenshell -import ifcopenshell.api -import ifcopenshell.util.element - - -class Usecase: - def __init__(self, file, product=None): - """Unassigns a container from a product. - - Caution: this API function may be replaced by spatial.unassign_container - - :param product: The IfcProduct to remove the containment from. - :type product: ifcopenshell.entity_instance.entity_instance - :return: None - :rtype: None - - Example: - - .. code:: python - - project = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcProject") - site = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcSite") - building = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcBuilding") - storey = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcBuildingStorey") - - # The project contains a site (note that project aggregation is a special case in IFC) - ifcopenshell.api.run("aggregate.assign_object", model, products=[site], relating_object=project) - - # The site has a building, the building has a storey, and the storey has a space - ifcopenshell.api.run("aggregate.assign_object", model, products=[building], relating_object=site) - ifcopenshell.api.run("aggregate.assign_object", model, products=[storey], relating_object=building) - - # Create a wall - wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall") - - # The wall is in the storey - ifcopenshell.api.run("spatial.assign_container", model, products=[wall], relating_structure=storey) - - # Not anymore! - ifcopenshell.api.run("spatial.remove_container", model, product=wall) - """ - self.file = file - self.settings = {"product": product} - - def execute(self): - contained_in_structure = self.settings["product"].ContainedInStructure - if not contained_in_structure: - return - - related_elements = list(contained_in_structure[0].RelatedElements) - related_elements.remove(self.settings["product"]) - if related_elements: - contained_in_structure[0].RelatedElements = related_elements - ifcopenshell.api.run("owner.update_owner_history", self.file, **{"element": contained_in_structure[0]}) - else: - history = contained_in_structure[0].OwnerHistory - self.file.remove(contained_in_structure[0]) - if history: - ifcopenshell.util.element.remove_deep2(self.file, history) diff --git a/src/ifcopenshell-python/test/api/spatial/test_remove_container.py b/src/ifcopenshell-python/test/api/spatial/test_remove_container.py deleted file mode 100644 index 7054c1fd48..0000000000 --- a/src/ifcopenshell-python/test/api/spatial/test_remove_container.py +++ /dev/null @@ -1,54 +0,0 @@ -# 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 numpy -import pytest -import test.bootstrap -import ifcopenshell.api -import ifcopenshell.util.element -import ifcopenshell.util.placement - - -class TestRemoveContainer(test.bootstrap.IFC4): - def test_removing_a_container(self): - element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding") - subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("spatial.assign_container", self.file, products=[subelement], relating_structure=element) - ifcopenshell.api.run("spatial.remove_container", self.file, product=subelement) - assert ifcopenshell.util.element.get_container(subelement) is None - - def test_doing_nothing_if_no_container(self): - subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("spatial.remove_container", self.file, product=subelement) - assert ifcopenshell.util.element.get_container(subelement) is None - - def test_updating_the_rel_when_a_container_is_removed_with_multipled_elements(self): - element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding") - subelement1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - subelement2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("spatial.assign_container", self.file, products=[subelement1], relating_structure=element) - ifcopenshell.api.run("spatial.assign_container", self.file, products=[subelement2], relating_structure=element) - ifcopenshell.api.run("spatial.remove_container", self.file, product=subelement1) - assert self.file.by_type("IfcRelContainedInSpatialStructure")[0].RelatedElements == (subelement2,) - - def test_deleting_the_rel_when_a_container_is_removed_with_no_elements(self): - element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding") - subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") - ifcopenshell.api.run("spatial.assign_container", self.file, products=[subelement], relating_structure=element) - ifcopenshell.api.run("spatial.remove_container", self.file, product=subelement) - assert len(self.file.by_type("IfcRelContainedInSpatialStructure")) == 0 diff --git a/src/ifcopenshell-python/test/api/spatial/test_unassign_container.py b/src/ifcopenshell-python/test/api/spatial/test_unassign_container.py index 4c06d4251d..033b5cd333 100644 --- a/src/ifcopenshell-python/test/api/spatial/test_unassign_container.py +++ b/src/ifcopenshell-python/test/api/spatial/test_unassign_container.py @@ -24,7 +24,7 @@ import ifcopenshell.util.element import ifcopenshell.util.placement -class TestAssignContainer(test.bootstrap.IFC4): +class TestUnassignContainer(test.bootstrap.IFC4): def test_unassigning_a_container(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding") subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") @@ -35,7 +35,12 @@ class TestAssignContainer(test.bootstrap.IFC4): ifcopenshell.api.run("spatial.unassign_container", self.file, products=[subelement, subelement2]) assert not self.file.by_type("IfcRelContainedInSpatialStructure") - def test_unassigning_a_container_with_other_elements(self): + def test_doing_nothing_if_no_container(self): + subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + ifcopenshell.api.run("spatial.unassign_container", self.file, products=[subelement]) + assert ifcopenshell.util.element.get_container(subelement) is None + + def test_updating_the_rel_when_a_container_is_removed_with_multipled_elements(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding") subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") subelement2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") @@ -45,3 +50,10 @@ class TestAssignContainer(test.bootstrap.IFC4): ifcopenshell.api.run("spatial.unassign_container", self.file, products=[subelement]) rel = self.file.by_type("IfcRelContainedInSpatialStructure")[0] assert list(rel.RelatedElements) == [subelement2] + + def test_deleting_the_rel_when_a_container_is_removed_with_no_elements(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding") + subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + ifcopenshell.api.run("spatial.assign_container", self.file, products=[subelement], relating_structure=element) + ifcopenshell.api.run("spatial.unassign_container", self.file, products=[subelement]) + assert len(self.file.by_type("IfcRelContainedInSpatialStructure")) == 0 diff --git a/src/ifcopenshell-python/test/api/test_api.py b/src/ifcopenshell-python/test/api/test_api.py index b3a1a1ba73..ccd55141ae 100644 --- a/src/ifcopenshell-python/test/api/test_api.py +++ b/src/ifcopenshell-python/test/api/test_api.py @@ -100,3 +100,10 @@ class TestTemporarySupportForDeprecatedAPIArguments(test.bootstrap.IFC4): ifcopenshell.api.run("aggregate.unassign_object", self.file, product=subelement) assert ifcopenshell.util.element.get_aggregate(subelement) is None + @deprecation_check + def test_removing_a_container(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding") + subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + ifcopenshell.api.run("spatial.assign_container", self.file, products=[subelement], relating_structure=element) + ifcopenshell.api.run("spatial.remove_container", self.file, product=subelement) + assert ifcopenshell.util.element.get_container(subelement) is None