mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
IfcTester now supports list and enumerated properties
This commit is contained in:
@@ -95,9 +95,9 @@ def get_properties(properties):
|
||||
if prop.is_a("IfcPropertySingleValue"):
|
||||
results[prop.Name] = prop.NominalValue.wrappedValue if prop.NominalValue else None
|
||||
elif prop.is_a("IfcPropertyEnumeratedValue"):
|
||||
values = [v.wrappedValue for v in prop.EnumerationValues]
|
||||
results[prop.Name] = [v.wrappedValue for v in prop.EnumerationValues] or None
|
||||
|
||||
elif prop.is_a("IfcPropertyListValue"):
|
||||
results[prop.Name] = [v.wrappedValue for v in prop.ListValues] or None
|
||||
elif prop.is_a("IfcComplexProperty"):
|
||||
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)
|
||||
|
||||
@@ -337,6 +337,10 @@ def get_property_unit(prop, ifc_file):
|
||||
measure_class = entity.attribute_by_index(3).type_of_attribute().declared_type().name()
|
||||
elif prop.is_a("IfcPropertySingleValue") and prop.NominalValue:
|
||||
measure_class = prop.NominalValue.is_a()
|
||||
elif prop.is_a("IfcPropertyEnumeratedValue") and prop.EnumerationValues:
|
||||
measure_class = prop.EnumerationValues[0].is_a()
|
||||
elif prop.is_a("IfcPropertyListValue") and prop.ListValues:
|
||||
measure_class = prop.ListValues[0].is_a()
|
||||
unit_type = get_measure_unit_type(measure_class)
|
||||
units = [u for u in unit_assignment.Units if getattr(u, "UnitType", None) == unit_type]
|
||||
if units:
|
||||
|
||||
@@ -460,13 +460,11 @@ class Property(Facet):
|
||||
|
||||
pset_entity = inst.wrapped_data.file.by_id(pset_props["id"])
|
||||
|
||||
is_property_supported_class = False
|
||||
is_property_supported_class = True
|
||||
for prop_entity in self.get_properties(pset_entity):
|
||||
if prop_entity.Name not in props[pset_name].keys():
|
||||
continue
|
||||
if prop_entity.is_a("IfcPropertySingleValue"):
|
||||
if prop_entity.Name not in props[pset_name].keys() or prop_entity.NominalValue is None:
|
||||
continue
|
||||
is_property_supported_class = True
|
||||
|
||||
data_type = prop_entity.NominalValue.is_a()
|
||||
|
||||
if data_type != self.measure:
|
||||
@@ -484,10 +482,6 @@ class Property(Facet):
|
||||
ifcopenshell.util.unit.si_type_names[unit.UnitType],
|
||||
)
|
||||
elif prop_entity.is_a("IfcPhysicalSimpleQuantity"):
|
||||
if prop_entity.Name not in props[pset_name].keys():
|
||||
continue
|
||||
is_property_supported_class = True
|
||||
|
||||
prop_schema = prop_entity.wrapped_data.declaration().as_entity()
|
||||
data_type = prop_schema.attribute_by_index(3).type_of_attribute().declared_type().name()
|
||||
|
||||
@@ -505,6 +499,27 @@ class Property(Facet):
|
||||
None,
|
||||
ifcopenshell.util.unit.si_type_names[unit.UnitType],
|
||||
)
|
||||
elif prop_entity.is_a("IfcPropertyEnumeratedValue"):
|
||||
data_type = prop_entity.EnumerationValues[0].is_a()
|
||||
if data_type != self.measure:
|
||||
is_pass = False
|
||||
reason = {"type": "MEASURE", "actual": data_type}
|
||||
break
|
||||
elif prop_entity.is_a("IfcPropertyListValue"):
|
||||
if not prop_entity.ListValues:
|
||||
is_pass = False
|
||||
reason = {"type": "NOVALUE"}
|
||||
break
|
||||
data_type = prop_entity.ListValues[0].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 unit:
|
||||
props[pset_name][prop_entity.Name] = [ifcopenshell.util.unit.convert(v, getattr(unit, "Prefix", None), unit.Name, None, ifcopenshell.util.unit.si_type_names[unit.UnitType]) for v in props[pset_name][prop_entity.Name]]
|
||||
else:
|
||||
is_property_supported_class = False
|
||||
|
||||
if not is_property_supported_class:
|
||||
is_pass = False
|
||||
@@ -516,11 +531,26 @@ class Property(Facet):
|
||||
if self.value:
|
||||
for value in props[pset_name].values():
|
||||
if isinstance(self.value, str) and isinstance(value, str):
|
||||
# "i_require_foo" = "i_have_bar"
|
||||
if value != self.value:
|
||||
is_pass = False
|
||||
reason = {"type": "VALUE", "actual": value}
|
||||
break
|
||||
elif isinstance(self.value, str) and isinstance(value, list):
|
||||
# "i_require_foo" = ["a", "b"] such as in enumerated properties
|
||||
if self.value not in value:
|
||||
is_pass = False
|
||||
reason = {"type": "VALUE", "actual": value}
|
||||
break
|
||||
elif not isinstance(self.value, str) and isinstance(value, list):
|
||||
# XSD restriction = ["a", "b"] such as in enumerated properties
|
||||
does_any_pass = [v for v in value if v == self.value]
|
||||
if not does_any_pass:
|
||||
is_pass = False
|
||||
reason = {"type": "VALUE", "actual": value}
|
||||
break
|
||||
elif isinstance(self.value, str):
|
||||
# "42" = 42
|
||||
cast_value = cast_to_value(self.value, value)
|
||||
if isinstance(value, float) and isinstance(cast_value, float):
|
||||
if value < cast_value * (1.0 - 1e-6) or value > cast_value * (1.0 + 1e-6):
|
||||
@@ -532,6 +562,7 @@ class Property(Facet):
|
||||
reason = {"type": "VALUE", "actual": value}
|
||||
break
|
||||
elif value != self.value:
|
||||
# XSD restriction = whatever
|
||||
is_pass = False
|
||||
reason = {"type": "VALUE", "actual": value}
|
||||
break
|
||||
|
||||
@@ -1009,6 +1009,36 @@ class TestProperty:
|
||||
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)
|
||||
|
||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
||||
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Pset_WallCommon")
|
||||
pset_template = ifcopenshell.util.pset.get_template("IFC4").get_by_name("Pset_WallCommon")
|
||||
ifcopenshell.api.run(
|
||||
"pset.edit_pset",
|
||||
ifc,
|
||||
pset=pset,
|
||||
properties={"Status": ["EXISTING", "DEMOLISH"]},
|
||||
pset_template=pset_template,
|
||||
)
|
||||
facet = Property(propertySet="Pset_WallCommon", name="Status", value="EXISTING", measure="IfcLabel")
|
||||
run("Any matching value in an enumerated property will pass 1/3", facet=facet, inst=element, expected=True)
|
||||
facet = Property(propertySet="Pset_WallCommon", name="Status", value="DEMOLISH", measure="IfcLabel")
|
||||
run("Any matching value in an enumerated property will pass 2/3", facet=facet, inst=element, expected=True)
|
||||
facet = Property(propertySet="Pset_WallCommon", name="Status", value="NEW", measure="IfcLabel")
|
||||
run("Any matching value in an enumerated property will pass 3/3", facet=facet, inst=element, expected=False)
|
||||
|
||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
||||
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar")
|
||||
list_property = ifc.createIfcPropertyListValue(
|
||||
Name="Foo", ListValues=[ifc.createIfcLabel("X"), ifc.createIfcLabel("Y")]
|
||||
)
|
||||
pset.HasProperties = [list_property]
|
||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="X", measure="IfcLabel")
|
||||
run("Any matching value in a list property will pass 1/3", facet=facet, inst=element, expected=True)
|
||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="Y", measure="IfcLabel")
|
||||
run("Any matching value in a list property will pass 2/3", facet=facet, inst=element, expected=True)
|
||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="Z", measure="IfcLabel")
|
||||
run("Any matching value in a list property will pass 3/3", facet=facet, inst=element, expected=False)
|
||||
|
||||
facet = Property(propertySet="Foo_Bar", name="Foo", measure="IfcLengthMeasure")
|
||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
||||
qto = ifcopenshell.api.run("pset.add_qto", ifc, product=element, name="Foo_Bar")
|
||||
|
||||
Reference in New Issue
Block a user