From 083d9d3e3e160776536f64fe01bea89a6413e73f Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Tue, 10 May 2022 16:23:07 +1000 Subject: [PATCH] Implement attribute facet for IDS --- src/ifcopenshell-python/ifcopenshell/ids.py | 63 +++++++++++++++++++++ src/ifcopenshell-python/test/test_ids.py | 23 ++++++++ 2 files changed, 86 insertions(+) diff --git a/src/ifcopenshell-python/ifcopenshell/ids.py b/src/ifcopenshell-python/ifcopenshell/ids.py index 6134500e5b..dc8e400b27 100644 --- a/src/ifcopenshell-python/ifcopenshell/ids.py +++ b/src/ifcopenshell-python/ifcopenshell/ids.py @@ -523,6 +523,69 @@ class entity(facet): return facet_evaluation(inst.is_a(self.name), self.message % {"name": inst.is_a()}) +class attribute(facet): + """The IDS attribute facet""" + + parameters = ["name", "value", "location"] + + @staticmethod + def create(name=None, value=None, location="any"): + """Create an attribute facet that can be added to applicability or requirements of IDS specification. + + :param name: Attribute name, such as "Description" + :type name: str + :param value: Attribute value + :type value: str, optional + :param location: Where to check for the parameter. One of "any"|"instance"|"type", defaults to "any" + :type location: str, optional + :return: entity object + :rtype: entity + """ + + inst = attribute() + inst.name = name + inst.value = value + inst.location = location + return inst + + def asdict(self): + """Converts object to a dictionary, adding required attributes. + + :return: Xmlschema compliant dictionary. + :rtype: dict + """ + fac_dict = {"name": parameter_asdict(self.name)} + if self.value: + fac_dict["value"] = parameter_asdict(self.value) + if self.location: + fac_dict["@location"] = self.location + return fac_dict + + def __call__(self, inst, logger): + """Validate an ifc instance against that entity facet. + + :param inst: IFC entity element + :type inst: IFC entity + :param logger: Logging object + :type logger: logging + :return: result of the validation as bool and message + :rtype: facet_evaluation(bool, str) + """ + element_type = ifcopenshell.util.element.get_type(inst) + if self.location == "instance": + value = getattr(inst, self.name, None) + elif self.location == "type": + value = getattr(element_type, self.name, None) if element_type else None + elif self.location == "any": + value = getattr(element_type, self.name, None) if element_type else None + value = getattr(inst, self.name, value) + if self.value: + self.message = "foo" + return facet_evaluation(value == self.value, f"an entity with {self.name} set to '{value}'") + else: + return facet_evaluation(value, f"an entity with {self.name}") + + class classification(facet): """ The IDS classification facet by traversing the HasAssociations inverse attribute diff --git a/src/ifcopenshell-python/test/test_ids.py b/src/ifcopenshell-python/test/test_ids.py index 7dd46ca878..340fe9c870 100644 --- a/src/ifcopenshell-python/test/test_ids.py +++ b/src/ifcopenshell-python/test/test_ids.py @@ -152,11 +152,34 @@ class TestIdsAuthoring(unittest.TestCase): """Creating basic IDS""" + def test_creating_a_minimal_ids_and_validating(self): + specs = ids.ids(title="Title") + spec = ids.specification(name="Name") + spec.add_applicability(ids.entity.create(name="IfcWall")) + spec.add_requirement(ids.attribute.create(name="Name", value="Waldo")) + specs.specifications.append(spec) + assert "http://standards.buildingsmart.org/IDS" in specs.to_string() + + model = ifcopenshell.file() + model.createIfcWall(Name="Waldo") + specs.validate(model) + # TODO test this without resorting to hooking into logger output + def test_entity_create(self): e = ids.entity.create(name="Test_Name", predefinedType="Test_PredefinedType") self.assertEqual(e.name, "Test_Name") self.assertEqual(e.predefinedType, "Test_PredefinedType") + def test_attribute_create(self): + attribute = ids.attribute.create(name="Name", value="Value") + assert attribute.name == "Name" + assert attribute.value == "Value" + assert attribute.asdict() == { + "name": {"simpleValue": "Name"}, + "value": {"simpleValue": "Value"}, + "@location": "any", + } + def test_classification_create(self): c = ids.classification.create(location="any", value="Test_Value", system="Test_System") self.assertEqual(c.location, "any")