diff --git a/src/ifctester/ifctester/facet.py b/src/ifctester/ifctester/facet.py index 1ec889309d..865e0fe435 100644 --- a/src/ifctester/ifctester/facet.py +++ b/src/ifctester/ifctester/facet.py @@ -437,25 +437,24 @@ class Property(Facet): reason = {"type": "NOVALUE"} break - if self.measure: - pset_entity = inst.wrapped_data.file.by_id(pset_props["id"]) - for prop_entity in pset_entity.HasProperties: - if ( - prop_entity.Name not in props[pset_name].keys() - or not prop_entity.is_a("IfcPropertySingleValue") - or prop_entity.NominalValue is None - ): - continue + pset_entity = inst.wrapped_data.file.by_id(pset_props["id"]) + for prop_entity in pset_entity.HasProperties: + if ( + prop_entity.Name not in props[pset_name].keys() + or not prop_entity.is_a("IfcPropertySingleValue") + or prop_entity.NominalValue is None + ): + continue - data_type = prop_entity.NominalValue.is_a() + data_type = prop_entity.NominalValue.is_a() - if data_type != self.measure: - is_pass = False - reason = {"type": "MEASURE", "actual": data_type} - break - - unit = ifcopenshell.util.unit.get_property_unit(prop_entity, inst.wrapped_data.file) + if data_type != self.measure: + is_pass = False + reason = {"type": "MEASURE", "actual": data_type} + break + unit = ifcopenshell.util.unit.get_property_unit(prop_entity, inst.wrapped_data.file) + if unit: props[pset_name][prop_entity.Name] = ifcopenshell.util.unit.convert( prop_entity.NominalValue.wrappedValue, getattr(unit, "Prefix", None), diff --git a/src/ifctester/test/test_facet.py b/src/ifctester/test/test_facet.py index 28920a7870..e7aa454356 100644 --- a/src/ifctester/test/test_facet.py +++ b/src/ifctester/test/test_facet.py @@ -849,7 +849,7 @@ class TestProperty: timeunit = ifcopenshell.api.run("unit.add_si_unit", ifc, unit_type="TIMEUNIT", name="SECOND") ifcopenshell.api.run("unit.assign_unit", ifc, units=[lengthunit, areaunit, volumeunit, timeunit]) - facet = Property(propertySet="Foo_Bar", name="Foo") + facet = Property(propertySet="Foo_Bar", name="Foo", measure="IfcLabel") element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") run("Elements with no properties always fail", facet=facet, inst=element, expected=False) pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar") @@ -860,11 +860,14 @@ class TestProperty: ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Bar"}) run("A name check will match any property with any string value", facet=facet, inst=element, expected=True) ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ""}) + facet = Property(propertySet="Foo_Bar", name="Foo", measure="IfcLogical") run("An empty string is considered falsey and will not pass", facet=facet, inst=element, expected=False) ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcLogical("UNKNOWN")}) + facet = Property(propertySet="Foo_Bar", name="Foo", measure="IfcDuration") run("A logical unknown is considered falsey and will not pass", facet=facet, inst=element, expected=False) ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcDuration("P0D")}) run("A zero duration will pass", facet=facet, inst=element, expected=True) + facet = Property(propertySet="Foo_Bar", name="Foo", measure="IfcBoolean") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcBoolean(True)}) run("A property set to true will pass a name check", facet=facet, inst=element, expected=True) ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": False}) @@ -875,7 +878,7 @@ class TestProperty: expected=True, ) - facet = Property(propertySet="Foo_Bar", name="Foo", value="Bar") + facet = Property(propertySet="Foo_Bar", name="Foo", value="Bar", measure="IfcLabel") element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Bar"}) @@ -885,52 +888,54 @@ class TestProperty: ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Baz"}) run("Specifying a value fails against different values", facet=facet, inst=element, expected=False) - facet = Property(propertySet="Foo_Bar", name="Foo", value="♫") + facet = Property(propertySet="Foo_Bar", name="Foo", value="♫", measure="IfcLabel") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "♫"}) run("Non-ascii characters are treated without encoding", facet=facet, inst=element, expected=True) identifier = "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345" - facet = Property(propertySet="Foo_Bar", name="Foo", value=identifier + "_extra_characters") + facet = Property( + propertySet="Foo_Bar", name="Foo", value=identifier + "_extra_characters", measure="IfcIdentifier" + ) ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcIdentifier(identifier)}) run("IDS does not handle string truncation such as for identifiers", facet=facet, inst=element, expected=False) - facet = Property(propertySet="Foo_Bar", name="Foo", value="1") + facet = Property(propertySet="Foo_Bar", name="Foo", value="1", measure="IfcLabel") element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "1"}) run("A number specified as a string is treated as a string", facet=facet, inst=element, expected=True) - facet = Property(propertySet="Foo_Bar", name="Foo", value="42") + facet = Property(propertySet="Foo_Bar", name="Foo", value="42", measure="IfcInteger") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcInteger(42)}) run("Integer values are checked using type casting 1/4", facet=facet, inst=element, expected=True) - facet = Property(propertySet="Foo_Bar", name="Foo", value="42.") + facet = Property(propertySet="Foo_Bar", name="Foo", value="42.", measure="IfcInteger") run("Integer values are checked using type casting 2/4", facet=facet, inst=element, expected=True) - facet = Property(propertySet="Foo_Bar", name="Foo", value="42.0") + facet = Property(propertySet="Foo_Bar", name="Foo", value="42.0", measure="IfcInteger") run("Integer values are checked using type casting 3/4", facet=facet, inst=element, expected=True) - facet = Property(propertySet="Foo_Bar", name="Foo", value="42.3") + facet = Property(propertySet="Foo_Bar", name="Foo", value="42.3", measure="IfcInteger") run("Integer values are checked using type casting 4/4", facet=facet, inst=element, expected=False) - facet = Property(propertySet="Foo_Bar", name="Foo", value="42") + facet = Property(propertySet="Foo_Bar", name="Foo", value="42", measure="IfcReal") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcReal(42.0)}) run("Real values are checked using type casting 1/3", facet=facet, inst=element, expected=True) - facet = Property(propertySet="Foo_Bar", name="Foo", value="42.0") + facet = Property(propertySet="Foo_Bar", name="Foo", value="42.0", measure="IfcReal") run("Real values are checked using type casting 2/3", facet=facet, inst=element, expected=True) - facet = Property(propertySet="Foo_Bar", name="Foo", value="42.3") + facet = Property(propertySet="Foo_Bar", name="Foo", value="42.3", measure="IfcReal") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcReal(42.3)}) run("Real values are checked using type casting 3/3", facet=facet, inst=element, expected=True) - facet = Property(propertySet="Foo_Bar", name="Foo", value="42,3") + facet = Property(propertySet="Foo_Bar", name="Foo", value="42,3", measure="IfcReal") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcReal(42.3)}) run("Only specifically formatted numbers are allowed 1/4", facet=facet, inst=element, expected=False) - facet = Property(propertySet="Foo_Bar", name="Foo", value="123,4.5") + facet = Property(propertySet="Foo_Bar", name="Foo", value="123,4.5", measure="IfcReal") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcReal(1234.5)}) run("Only specifically formatted numbers are allowed 2/4", facet=facet, inst=element, expected=False) - facet = Property(propertySet="Foo_Bar", name="Foo", value="1.2345e3") + facet = Property(propertySet="Foo_Bar", name="Foo", value="1.2345e3", measure="IfcReal") run("Only specifically formatted numbers are allowed 3/4", facet=facet, inst=element, expected=True) - facet = Property(propertySet="Foo_Bar", name="Foo", value="1.2345E3") + facet = Property(propertySet="Foo_Bar", name="Foo", value="1.2345E3", measure="IfcReal") run("Only specifically formatted numbers are allowed 4/4", facet=facet, inst=element, expected=True) - facet = Property(propertySet="Foo_Bar", name="Foo", value="42.") + facet = Property(propertySet="Foo_Bar", name="Foo", value="42.", measure="IfcReal") ifcopenshell.api.run( "pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcReal(42.0 * (1.0 + 1e-6))} ) @@ -948,15 +953,15 @@ class TestProperty: ) run("Floating point numbers are compared with a 1e-6 tolerance 4/4", facet=facet, inst=element, expected=False) - facet = Property(propertySet="Foo_Bar", name="Foo", value="TRUE") + facet = Property(propertySet="Foo_Bar", name="Foo", value="TRUE", measure="IfcBoolean") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcBoolean(False)}) run("Booleans must be specified as uppercase strings 1/3", facet=facet, inst=element, expected=False) - facet = Property(propertySet="Foo_Bar", name="Foo", value="FALSE") + facet = Property(propertySet="Foo_Bar", name="Foo", value="FALSE", measure="IfcBoolean") run("Booleans must be specified as uppercase strings 2/3", facet=facet, inst=element, expected=True) - facet = Property(propertySet="Foo_Bar", name="Foo", value="False") + facet = Property(propertySet="Foo_Bar", name="Foo", value="False", measure="IfcBoolean") run("Booleans must be specified as uppercase strings 3/3", facet=facet, inst=element, expected=False) - facet = Property(propertySet="Foo_Bar", name="Foo", value="2022-01-01") + facet = Property(propertySet="Foo_Bar", name="Foo", value="2022-01-01", measure="IfcDate") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcDate("2022-01-01")}) run("Dates are treated as strings 1/2", facet=facet, inst=element, expected=True) ifcopenshell.api.run( @@ -964,14 +969,14 @@ class TestProperty: ) run("Dates are treated as strings 2/2", facet=facet, inst=element, expected=False) - facet = Property(propertySet="Foo_Bar", name="Foo", value="PT16H") + facet = Property(propertySet="Foo_Bar", name="Foo", value="PT16H", measure="IfcDuration") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcDuration("PT16H")}) run("Durations are treated as strings 1/2", facet=facet, inst=element, expected=True) ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcDuration("P2D")}) run("Durations are treated as strings 1/2", facet=facet, inst=element, expected=False) restriction = Restriction(options="Foo_.*", type="pattern") - facet = Property(propertySet=restriction, name="Foo") + facet = Property(propertySet=restriction, name="Foo", measure="IfcLabel") element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Bar"}) @@ -983,7 +988,7 @@ class TestProperty: run("All matching property sets must satisfy requirements 3/3", facet=facet, inst=element, expected=True) restriction = Restriction(options="Foo.*", type="pattern") - facet = Property(propertySet="Foo_Bar", name=restriction, value="x") + facet = Property(propertySet="Foo_Bar", name=restriction, value="x", measure="IfcLabel") element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foobar": "x"}) @@ -995,7 +1000,7 @@ class TestProperty: restriction1 = Restriction(options="Foo.*", type="pattern") restriction2 = Restriction(options=["x", "y"], type="enumeration") - facet = Property(propertySet="Foo_Bar", name=restriction1, value=restriction2) + facet = Property(propertySet="Foo_Bar", name=restriction1, value=restriction2, measure="IfcLabel") element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foobar": "x", "Foobaz": "y"}) @@ -1017,9 +1022,9 @@ class TestProperty: element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcMassMeasure(2)}) - run("Measure may be used to specify an IFC data type 1/2", facet=facet, inst=element, expected=False) + run("Measures are used to specify an IFC data type 1/2", facet=facet, inst=element, expected=False) ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcTimeMeasure(2)}) - run("Measure may be used to specify an IFC data type 2/2", facet=facet, inst=element, expected=True) + run("Measures are used to specify an IFC data type 2/2", facet=facet, inst=element, expected=True) facet = Property(propertySet="Foo_Bar", name="Foo", value="2", measure="IfcLengthMeasure") element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall") @@ -1044,7 +1049,7 @@ class TestProperty: ifcopenshell.api.run("type.assign_type", ifc, related_object=wall, relating_type=wall_type) pset = ifcopenshell.api.run("pset.add_pset", ifc, product=wall_type, name="Foo_Bar") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Bar"}) - facet = Property(propertySet="Foo_Bar", name="Foo") + facet = Property(propertySet="Foo_Bar", name="Foo", measure="IfcLabel") run("Properties can be inherited from the type 1/2", facet=facet, inst=wall, expected=True) run("Properties can be inherited from the type 2/2", facet=facet, inst=wall_type, expected=True) @@ -1055,7 +1060,7 @@ class TestProperty: ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Baz"}) pset = ifcopenshell.api.run("pset.add_pset", ifc, product=wall, name="Foo_Bar") ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Bar"}) - facet = Property(propertySet="Foo_Bar", name="Foo", value="Bar") + facet = Property(propertySet="Foo_Bar", name="Foo", value="Bar", measure="IfcLabel") run("Properties can be overriden by an occurrence 1/2", facet=facet, inst=wall, expected=True) run("Properties can be overriden by an occurrence 2/2", facet=facet, inst=wall_type, expected=False)