From 5990d6b66dc269107ead8a26bbf7e73f61bef191 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Tue, 31 Aug 2021 15:44:57 +1000 Subject: [PATCH] Test util.element module. See #1711. --- .../ifcopenshell/util/element.py | 5 +- src/ifcopenshell-python/test/__init__.py | 0 src/ifcopenshell-python/test/bootstrap.py | 17 ++ src/ifcopenshell-python/test/util/__init__.py | 0 .../test/util/test_element.py | 246 ++++++++++++++++++ 5 files changed, 266 insertions(+), 2 deletions(-) create mode 100644 src/ifcopenshell-python/test/__init__.py create mode 100644 src/ifcopenshell-python/test/bootstrap.py create mode 100644 src/ifcopenshell-python/test/util/__init__.py create mode 100644 src/ifcopenshell-python/test/util/test_element.py diff --git a/src/ifcopenshell-python/ifcopenshell/util/element.py b/src/ifcopenshell-python/ifcopenshell/util/element.py index 08d9aff9e6..f9cd4ef917 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/element.py +++ b/src/ifcopenshell-python/ifcopenshell/util/element.py @@ -26,7 +26,8 @@ def get_property_definition(definition): # Entity introduced in IFC4 # definition.is_a('IfcPreDefinedPropertySet'): for prop in range(4, len(definition)): - props[definition.attribute_name(prop)] = definition[prop] + if definition[prop] is not None: + props[definition.attribute_name(prop)] = definition[prop] return props @@ -44,7 +45,7 @@ def get_properties(properties): if prop.is_a("IfcPropertySingleValue"): results[prop.Name] = prop.NominalValue.wrappedValue if prop.NominalValue else None elif prop.is_a("IfcComplexProperty"): - data = prop.get_info() + data = {k: v for k, v in prop.get_info().items() if v is not None and k != "Name"} data["properties"] = get_properties(prop.HasProperties) del data["HasProperties"] results[prop.Name] = data diff --git a/src/ifcopenshell-python/test/__init__.py b/src/ifcopenshell-python/test/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/ifcopenshell-python/test/bootstrap.py b/src/ifcopenshell-python/test/bootstrap.py new file mode 100644 index 0000000000..b71e59ac00 --- /dev/null +++ b/src/ifcopenshell-python/test/bootstrap.py @@ -0,0 +1,17 @@ +import pytest +import ifcopenshell.api + + +class IFC4: + @pytest.fixture(autouse=True) + def setup(self): + self.file = ifcopenshell.api.run("project.create_file") + + +class IFC2X3: + @pytest.fixture(autouse=True) + def setup(self): + self.file = ifcopenshell.api.run("project.create_file", version="IFC2X3") + ifcopenshell.api.owner.settings.get_person = lambda ifc: ifc.createIfcPerson() + ifcopenshell.api.owner.settings.get_organisation = lambda ifc: ifc.createIfcOrganization() + ifcopenshell.api.owner.settings.get_application = lambda ifc: ifc.createIfcApplication() diff --git a/src/ifcopenshell-python/test/util/__init__.py b/src/ifcopenshell-python/test/util/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/ifcopenshell-python/test/util/test_element.py b/src/ifcopenshell-python/test/util/test_element.py new file mode 100644 index 0000000000..320f0a2287 --- /dev/null +++ b/src/ifcopenshell-python/test/util/test_element.py @@ -0,0 +1,246 @@ +import pytest +import test.bootstrap +import ifcopenshell.api +import ifcopenshell.util.element + + +class TestGetPsetsIFC4(test.bootstrap.IFC4): + def test_getting_the_psets_of_a_product_as_a_dictionary(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + assert ifcopenshell.util.element.get_psets(element) == {} + pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="name") + ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"a": "b"}) + assert ifcopenshell.util.element.get_psets(element) == {"name": {"a": "b"}} + + def test_getting_the_psets_of_a_product_type_as_a_dictionary(self): + type_element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + assert ifcopenshell.util.element.get_psets(type_element) == {} + pset = ifcopenshell.api.run("pset.add_pset", self.file, product=type_element, name="name") + ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"x": "y"}) + assert ifcopenshell.util.element.get_psets(type_element) == {"name": {"x": "y"}} + + def test_getting_psets_from_an_element_which_cannot_have_psets(self): + assert ifcopenshell.util.element.get_psets(self.file.create_entity("IfcPerson")) == {} + + +class TestGetPropertyDefinitionIFC4(test.bootstrap.IFC4): + def test_getting_the_properties_of_a_pset(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="name") + ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"a": "b"}) + assert ifcopenshell.util.element.get_property_definition(pset) == {"a": "b"} + + def test_getting_the_properties_of_a_qto(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + qto = ifcopenshell.api.run("pset.add_qto", self.file, product=element, name="name") + ifcopenshell.api.run("pset.edit_qto", self.file, qto=qto, properties={"x": 42}) + assert ifcopenshell.util.element.get_property_definition(qto) == {"x": 42} + + def test_getting_the_properties_of_a_predefined_pset(self): + pset = self.file.create_entity("IfcDoorLiningProperties", ifcopenshell.guid.new()) + pset.LiningDepth = 42 + assert ifcopenshell.util.element.get_property_definition(pset) == {"LiningDepth": 42} + + +class TestGetQuantitiesIFC4(test.bootstrap.IFC4): + def test_getting_quantities_from_a_qto(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + qto = ifcopenshell.api.run("pset.add_qto", self.file, product=element, name="name") + ifcopenshell.api.run("pset.edit_qto", self.file, qto=qto, properties={"x": 42}) + assert ifcopenshell.util.element.get_quantities(qto.Quantities) == {"x": 42} + + +class TestGetPropertiesIFC4(test.bootstrap.IFC4): + def test_getting_single_properties_from_a_list_of_properties(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="name") + ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"a": "b"}) + assert ifcopenshell.util.element.get_properties(pset.HasProperties) == {"a": "b"} + + def test_getting_complex_properties_from_a_list_of_properties(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="pset") + complex_property = self.file.createIfcComplexProperty(Name="prop", UsageName="usage_name") + ifcopenshell.api.run("pset.edit_pset", self.file, pset=complex_property, properties={"a": "b"}) + pset.HasProperties = [complex_property] + assert ifcopenshell.util.element.get_properties(pset.HasProperties) == { + "prop": { + "UsageName": "usage_name", + "id": 4, + "type": "IfcComplexProperty", + "properties": {"a": "b"}, + } + } + + +class TestGetTypeIFC4(test.bootstrap.IFC4): + def test_getting_the_type_of_a_product(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + assert ifcopenshell.util.element.get_type(element) == element_type + assert ifcopenshell.util.element.get_type(element_type) == element_type + + +class TestGetTypeIFC2X3(test.bootstrap.IFC2X3): + def test_getting_the_type_of_a_product(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + assert ifcopenshell.util.element.get_type(element) == element_type + assert ifcopenshell.util.element.get_type(element_type) == element_type + + +class TestGetMaterial(test.bootstrap.IFC4): + def test_getting_the_material_of_a_product(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + material = ifcopenshell.api.run("material.add_material", self.file) + ifcopenshell.api.run("material.assign_material", self.file, product=element, material=material) + assert ifcopenshell.util.element.get_material(element) == material + + def test_getting_a_material_list_of_a_product(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + material = ifcopenshell.api.run("material.add_material", self.file) + rel = ifcopenshell.api.run( + "material.assign_material", self.file, product=element, type="IfcMaterialList", material=material + ) + assert ifcopenshell.util.element.get_material(element) == rel.RelatingMaterial + + def test_getting_a_material_layer_set_of_a_product(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + rel = ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialLayerSet") + assert ifcopenshell.util.element.get_material(element) == rel.RelatingMaterial + + def test_getting_a_material_profile_set_of_a_product(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + rel = ifcopenshell.api.run("material.assign_material", self.file, product=element, type="IfcMaterialProfileSet") + assert ifcopenshell.util.element.get_material(element) == rel.RelatingMaterial + + def test_getting_a_material_layer_set_usage_of_a_product(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + rel = ifcopenshell.api.run( + "material.assign_material", self.file, product=element, type="IfcMaterialLayerSetUsage" + ) + assert ifcopenshell.util.element.get_material(element) == rel.RelatingMaterial + + def test_getting_a_material_profile_set_usage_of_a_product(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + rel = ifcopenshell.api.run( + "material.assign_material", self.file, product=element, type="IfcMaterialProfileSetUsage" + ) + assert ifcopenshell.util.element.get_material(element) == rel.RelatingMaterial + + def test_getting_a_material_layer_set_indirectly_from_an_assigned_usage(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + rel = ifcopenshell.api.run( + "material.assign_material", self.file, product=element, type="IfcMaterialLayerSetUsage" + ) + assert ( + ifcopenshell.util.element.get_material(element, should_skip_usage=True) == rel.RelatingMaterial.ForLayerSet + ) + + def test_getting_a_material_profile_set_indirectly_from_an_assigned_usage(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + rel = ifcopenshell.api.run( + "material.assign_material", self.file, product=element, type="IfcMaterialProfileSetUsage" + ) + assert ( + ifcopenshell.util.element.get_material(element, should_skip_usage=True) + == rel.RelatingMaterial.ForProfileSet + ) + + def test_getting_an_inherited_material_from_the_elements_type(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType") + ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=element_type) + material = ifcopenshell.api.run("material.add_material", self.file) + ifcopenshell.api.run("material.assign_material", self.file, product=element_type, material=material) + assert ifcopenshell.util.element.get_material(element) == material + + +class TestGetContainerIFC4(test.bootstrap.IFC4): + def test_getting_the_spatial_container_of_an_element(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + building = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBuilding") + ifcopenshell.api.run("spatial.assign_container", self.file, product=element, relating_structure=building) + assert ifcopenshell.util.element.get_container(element) == building + + +class TestGetAggregateIFC4(test.bootstrap.IFC4): + def test_getting_the_containing_aggregate_of_a_subelement(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcCovering") + ifcopenshell.api.run("aggregate.assign_object", self.file, product=subelement, relating_object=element) + assert ifcopenshell.util.element.get_aggregate(subelement) == element + + +class TestReplaceAttributeIFC4(test.bootstrap.IFC4): + def test_replacing_an_elements_attribute(self): + element = self.file.createIfcWall("foo") + ifcopenshell.util.element.replace_attribute(element, "foo", "bar") + assert element.GlobalId == "bar" + + def test_replacing_a_value_in_a_list(self): + old = self.file.createIfcWall() + new = self.file.createIfcWall() + rel = self.file.createIfcRelAggregates() + rel.RelatedObjects = [old] + ifcopenshell.util.element.replace_attribute(rel, old, new) + assert rel.RelatedObjects == (new,) + + +class TestHasElementReferenceIFC4(test.bootstrap.IFC4): + def test_if_a_element_attribute_references_another_element(self): + old = self.file.createIfcWall() + new = self.file.createIfcWall() + rel = self.file.createIfcRelAggregates() + rel.RelatedObjects = [old] + assert ifcopenshell.util.element.has_element_reference(rel.RelatedObjects, old) is True + assert ifcopenshell.util.element.has_element_reference(rel.RelatedObjects, new) is False + + +class TestRemoveDeepIFC4(test.bootstrap.IFC4): + def test_removing_an_element_along_with_all_direct_attributes_recursively(self): + owner = self.file.createIfcOwnerHistory() + element = self.file.createIfcWall(GlobalId="id", OwnerHistory=owner) + ifcopenshell.util.element.remove_deep(self.file, element) + with pytest.raises(RuntimeError): + self.file.by_id(1) + self.file.by_id(2) + + def test_removing_an_element_recursively_except_if_an_element_is_referenced_elsewhere(self): + owner = self.file.createIfcOwnerHistory() + element = self.file.createIfcWall(GlobalId="id1", OwnerHistory=owner) + element2 = self.file.createIfcWall(GlobalId="id2", OwnerHistory=owner) + ifcopenshell.util.element.remove_deep(self.file, element) + with pytest.raises(RuntimeError): + self.file.by_guid("id1") + assert self.file.by_id(1) + assert self.file.by_guid("id2") + + +class TestCopyIFC4(test.bootstrap.IFC4): + def test_copying_an_element(self): + element = self.file.createIfcWall(GlobalId="id", Name="name") + element2 = ifcopenshell.util.element.copy(self.file, element) + assert element.is_a() == element2.is_a() + assert element.GlobalId != element2.GlobalId + assert element.Name == element2.Name + + +class TestCopyDeepIFC4(test.bootstrap.IFC4): + def test_copying_an_element_recursively(self): + owner = self.file.createIfcOwnerHistory() + owner.State = "READWRITE" + element = self.file.createIfcWall(GlobalId="id", Name="name", OwnerHistory=owner) + element2 = ifcopenshell.util.element.copy_deep(self.file, element) + assert element.OwnerHistory != element2.OwnerHistory + assert element.OwnerHistory.State == element2.OwnerHistory.State + + def test_copying_an_element_recursively_even_if_references_are_aggregated(self): + element = self.file.createIfcWall(Name="name") + rel = self.file.createIfcRelAggregates() + rel.RelatedObjects = [element] + rel2 = ifcopenshell.util.element.copy_deep(self.file, rel) + assert rel.RelatedObjects != rel2.RelatedObjects + assert rel.RelatedObjects[0].Name == rel2.RelatedObjects[0].Name