mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Fix #4465. Update IfcTester to IDS 0.9.7
This commit is contained in:
@@ -16,14 +16,13 @@ my_ids = ids.Ids(title="My IDS")
|
|||||||
my_spec = ids.Specification(name="My first specification")
|
my_spec = ids.Specification(name="My first specification")
|
||||||
my_spec.applicability.append(ids.Entity(name="IFCWALL"))
|
my_spec.applicability.append(ids.Entity(name="IFCWALL"))
|
||||||
property = ids.Property(
|
property = ids.Property(
|
||||||
name="IsExternal",
|
baseName="IsExternal",
|
||||||
value="TRUE",
|
value="TRUE",
|
||||||
propertySet="Pset_WallCommon",
|
propertySet="Pset_WallCommon",
|
||||||
datatype="IfcBoolean",
|
dataType="IfcBoolean",
|
||||||
uri="https://identifier.buildingsmart.org/uri/.../prop/LoadBearing",
|
uri="https://identifier.buildingsmart.org/uri/.../prop/LoadBearing",
|
||||||
instructions="Walls need to be load bearing.",
|
instructions="Walls need to be load bearing.",
|
||||||
minOccurs=1,
|
cardinality="required")
|
||||||
maxOccurs="unbounded")
|
|
||||||
my_spec.requirements.append(property)
|
my_spec.requirements.append(property)
|
||||||
my_ids.specifications.append(my_spec)
|
my_ids.specifications.append(my_spec)
|
||||||
|
|
||||||
|
|||||||
@@ -66,22 +66,22 @@ class Facet:
|
|||||||
for name in self.parameters:
|
for name in self.parameters:
|
||||||
value = getattr(self, name.replace("@", ""))
|
value = getattr(self, name.replace("@", ""))
|
||||||
if value is not None:
|
if value is not None:
|
||||||
|
if name == "@dataType":
|
||||||
|
value = value.upper()
|
||||||
results[name] = value if "@" in name else self.to_ids_value(value)
|
results[name] = value if "@" in name else self.to_ids_value(value)
|
||||||
if clause_type == "applicability":
|
if clause_type == "applicability":
|
||||||
for key in ["@uri", "@instructions", "@minOccurs", "@maxOccurs"]:
|
for key in ["@uri", "@instructions", "@cardinality"]:
|
||||||
results.pop(key, None)
|
results.pop(key, None)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def parse(self, xml):
|
def parse(self, xml):
|
||||||
setattr(self, "minOccurs", 1)
|
setattr(self, "cardinality", "required")
|
||||||
setattr(self, "maxOccurs", 1)
|
|
||||||
for name, value in xml.items():
|
for name, value in xml.items():
|
||||||
name = name.replace("@", "")
|
name = name.replace("@", "")
|
||||||
if isinstance(value, dict) and "simpleValue" in value.keys():
|
if isinstance(value, dict) and "simpleValue" in value.keys():
|
||||||
setattr(self, name, value["simpleValue"])
|
setattr(self, name, value["simpleValue"])
|
||||||
elif isinstance(value, dict) and "restriction" in value.keys():
|
elif isinstance(value, dict) and "restriction" in value.keys():
|
||||||
setattr(self, name, Restriction().parse(value["restriction"][0]))
|
setattr(self, name, Restriction().parse(value["restriction"][0]))
|
||||||
# TODO handle more than one restriction: return [restriction(r) for r in v["restriction"]]
|
|
||||||
else:
|
else:
|
||||||
setattr(self, name, value)
|
setattr(self, name, value)
|
||||||
return self
|
return self
|
||||||
@@ -96,9 +96,9 @@ class Facet:
|
|||||||
templates = self.applicability_templates
|
templates = self.applicability_templates
|
||||||
elif clause_type == "requirement":
|
elif clause_type == "requirement":
|
||||||
is_prohibited = False
|
is_prohibited = False
|
||||||
if specification.maxOccurs == 0:
|
if specification.cardinality == "prohibited":
|
||||||
is_prohibited = not is_prohibited
|
is_prohibited = not is_prohibited
|
||||||
if requirement.maxOccurs == 0:
|
if requirement.cardinality == "prohibited":
|
||||||
is_prohibited = not is_prohibited
|
is_prohibited = not is_prohibited
|
||||||
templates = self.prohibited_templates if is_prohibited else self.requirement_templates
|
templates = self.prohibited_templates if is_prohibited else self.requirement_templates
|
||||||
|
|
||||||
@@ -131,12 +131,7 @@ class Facet:
|
|||||||
return parameter_dict
|
return parameter_dict
|
||||||
|
|
||||||
def get_usage(self):
|
def get_usage(self):
|
||||||
if self.minOccurs != 0:
|
return self.cardinality
|
||||||
return "required"
|
|
||||||
elif self.minOccurs == 0 and self.maxOccurs != 0:
|
|
||||||
return "optional"
|
|
||||||
elif self.maxOccurs == 0:
|
|
||||||
return "prohibited"
|
|
||||||
|
|
||||||
|
|
||||||
class Entity(Facet):
|
class Entity(Facet):
|
||||||
@@ -197,8 +192,8 @@ class Entity(Facet):
|
|||||||
|
|
||||||
|
|
||||||
class Attribute(Facet):
|
class Attribute(Facet):
|
||||||
def __init__(self, name="Name", value=None, minOccurs=None, maxOccurs=None, instructions=None):
|
def __init__(self, name="Name", value=None, cardinality="required", instructions=None):
|
||||||
self.parameters = ["name", "value", "@minOccurs", "@maxOccurs", "@instructions"]
|
self.parameters = ["name", "value", "@cardinality", "@instructions"]
|
||||||
self.applicability_templates = [
|
self.applicability_templates = [
|
||||||
"Data where the {name} is {value}",
|
"Data where the {name} is {value}",
|
||||||
"Data where the {name} is provided",
|
"Data where the {name} is provided",
|
||||||
@@ -211,7 +206,7 @@ class Attribute(Facet):
|
|||||||
"The {name} shall not be {value}",
|
"The {name} shall not be {value}",
|
||||||
"The {name} shall not be provided",
|
"The {name} shall not be provided",
|
||||||
]
|
]
|
||||||
super().__init__(name, value, minOccurs, maxOccurs, instructions)
|
super().__init__(name, value, cardinality, instructions)
|
||||||
|
|
||||||
def filter(
|
def filter(
|
||||||
self, ifc_file: ifcopenshell.file, elements: Union[ifcopenshell.entity_instance, None]
|
self, ifc_file: ifcopenshell.file, elements: Union[ifcopenshell.entity_instance, None]
|
||||||
@@ -242,7 +237,7 @@ class Attribute(Facet):
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
def __call__(self, inst, logger=None):
|
def __call__(self, inst, logger=None):
|
||||||
if self.minOccurs == 0 and self.maxOccurs != 0:
|
if self.cardinality == "optional":
|
||||||
return AttributeResult(True)
|
return AttributeResult(True)
|
||||||
|
|
||||||
if isinstance(self.name, str):
|
if isinstance(self.name, str):
|
||||||
@@ -323,34 +318,31 @@ class Attribute(Facet):
|
|||||||
reason = {"type": "VALUE", "actual": value}
|
reason = {"type": "VALUE", "actual": value}
|
||||||
break
|
break
|
||||||
|
|
||||||
if self.maxOccurs == 0:
|
if self.cardinality == "prohibited":
|
||||||
return AttributeResult(not is_pass, {"type": "PROHIBITED"})
|
return AttributeResult(not is_pass, {"type": "PROHIBITED"})
|
||||||
return AttributeResult(is_pass, reason)
|
return AttributeResult(is_pass, reason)
|
||||||
|
|
||||||
|
|
||||||
class Classification(Facet):
|
class Classification(Facet):
|
||||||
def __init__(self, value=None, system=None, uri=None, minOccurs=None, maxOccurs="unbounded", instructions=None):
|
def __init__(self, value=None, system=None, uri=None, cardinality="required", instructions=None):
|
||||||
self.parameters = ["value", "system", "@uri", "@minOccurs", "@maxOccurs", "@instructions"]
|
self.parameters = ["value", "system", "@uri", "@cardinality", "@instructions"]
|
||||||
self.applicability_templates = [
|
self.applicability_templates = [
|
||||||
"Data having a {system} reference of {value}",
|
"Data having a {system} reference of {value}",
|
||||||
"Data classified using {system}",
|
"Data classified using {system}",
|
||||||
"Data classified as {value}",
|
"Data classified as {value}",
|
||||||
"Classified data",
|
|
||||||
]
|
]
|
||||||
self.requirement_templates = [
|
self.requirement_templates = [
|
||||||
"Shall have a {system} reference of {value}",
|
"Shall have a {system} reference of {value}",
|
||||||
"Shall be classified using {system}",
|
"Shall be classified using {system}",
|
||||||
"Shall be classified as {value}",
|
"Shall be classified as {value}",
|
||||||
"Shall be classified",
|
|
||||||
]
|
]
|
||||||
self.prohibited_templates = [
|
self.prohibited_templates = [
|
||||||
"Shall not have a {system} reference of {value}",
|
"Shall not have a {system} reference of {value}",
|
||||||
"Shall not be classified using {system}",
|
"Shall not be classified using {system}",
|
||||||
"Shall not be classified as {value}",
|
"Shall not be classified as {value}",
|
||||||
"Shall not be classified",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
super().__init__(value, system, uri, minOccurs, maxOccurs, instructions)
|
super().__init__(value, system, uri, cardinality, instructions)
|
||||||
|
|
||||||
def filter(
|
def filter(
|
||||||
self, ifc_file: ifcopenshell.file, elements: Union[ifcopenshell.entity_instance, None]
|
self, ifc_file: ifcopenshell.file, elements: Union[ifcopenshell.entity_instance, None]
|
||||||
@@ -360,8 +352,8 @@ class Classification(Facet):
|
|||||||
return ifc_file.by_type("IfcObjectDefinition")
|
return ifc_file.by_type("IfcObjectDefinition")
|
||||||
|
|
||||||
def __call__(self, inst, logger=None):
|
def __call__(self, inst, logger=None):
|
||||||
if self.minOccurs == 0 and self.maxOccurs != 0:
|
if self.cardinality == "optional":
|
||||||
return ClassificationResult(True)
|
return ClassificationResult(True) # Is this really the correct behaviour?
|
||||||
|
|
||||||
leaf_references = ifcopenshell.util.classification.get_references(inst)
|
leaf_references = ifcopenshell.util.classification.get_references(inst)
|
||||||
|
|
||||||
@@ -381,13 +373,13 @@ class Classification(Facet):
|
|||||||
if not is_pass:
|
if not is_pass:
|
||||||
reason = {"type": "VALUE", "actual": values}
|
reason = {"type": "VALUE", "actual": values}
|
||||||
|
|
||||||
if is_pass and self.system:
|
if is_pass:
|
||||||
systems = [ifcopenshell.util.classification.get_classification(r).Name for r in references]
|
systems = [ifcopenshell.util.classification.get_classification(r).Name for r in references]
|
||||||
is_pass = any([self.system == s for s in systems])
|
is_pass = any([self.system == s for s in systems])
|
||||||
if not is_pass:
|
if not is_pass:
|
||||||
reason = {"type": "SYSTEM", "actual": systems}
|
reason = {"type": "SYSTEM", "actual": systems}
|
||||||
|
|
||||||
if self.maxOccurs == 0:
|
if self.cardinality == "prohibited":
|
||||||
return ClassificationResult(not is_pass, {"type": "PROHIBITED"})
|
return ClassificationResult(not is_pass, {"type": "PROHIBITED"})
|
||||||
return ClassificationResult(is_pass, reason)
|
return ClassificationResult(is_pass, reason)
|
||||||
|
|
||||||
@@ -398,11 +390,10 @@ class PartOf(Facet):
|
|||||||
name="IFCWALL",
|
name="IFCWALL",
|
||||||
predefinedType=None,
|
predefinedType=None,
|
||||||
relation=None,
|
relation=None,
|
||||||
minOccurs=None,
|
cardinality="required",
|
||||||
maxOccurs="unbounded",
|
|
||||||
instructions=None,
|
instructions=None,
|
||||||
):
|
):
|
||||||
self.parameters = ["name", "predefinedType", "@relation", "@minOccurs", "@maxOccurs", "@instructions"]
|
self.parameters = ["name", "predefinedType", "@relation", "@cardinality", "@instructions"]
|
||||||
self.applicability_templates = [
|
self.applicability_templates = [
|
||||||
"An element with an {relation} relationship with an {name}",
|
"An element with an {relation} relationship with an {name}",
|
||||||
"An element with an {relation} relationship",
|
"An element with an {relation} relationship",
|
||||||
@@ -415,7 +406,7 @@ class PartOf(Facet):
|
|||||||
"An element must not have an {relation} relationship with an {name}",
|
"An element must not have an {relation} relationship with an {name}",
|
||||||
"An element must not have an {relation} relationship",
|
"An element must not have an {relation} relationship",
|
||||||
]
|
]
|
||||||
super().__init__(name, predefinedType, relation, minOccurs, maxOccurs, instructions)
|
super().__init__(name, predefinedType, relation, cardinality, instructions)
|
||||||
|
|
||||||
def filter(
|
def filter(
|
||||||
self, ifc_file: ifcopenshell.file, elements: Union[ifcopenshell.entity_instance, None]
|
self, ifc_file: ifcopenshell.file, elements: Union[ifcopenshell.entity_instance, None]
|
||||||
@@ -444,9 +435,6 @@ class PartOf(Facet):
|
|||||||
return super().parse(xml)
|
return super().parse(xml)
|
||||||
|
|
||||||
def __call__(self, inst, logger=None):
|
def __call__(self, inst, logger=None):
|
||||||
if self.minOccurs == 0 and self.maxOccurs != 0:
|
|
||||||
return PartOfResult(True)
|
|
||||||
|
|
||||||
reason = None
|
reason = None
|
||||||
if not self.relation:
|
if not self.relation:
|
||||||
is_pass = False
|
is_pass = False
|
||||||
@@ -536,8 +524,14 @@ class PartOf(Facet):
|
|||||||
nest = self.get_nested_whole(nest)
|
nest = self.get_nested_whole(nest)
|
||||||
if not is_pass:
|
if not is_pass:
|
||||||
reason = {"type": "ENTITY", "actual": ancestors}
|
reason = {"type": "ENTITY", "actual": ancestors}
|
||||||
elif self.relation == "IFCRELVOIDSELEMENT":
|
elif self.relation == "IFCRELVOIDSELEMENT IFCRELFILLSELEMENT":
|
||||||
building_element = self.get_voided_element(inst)
|
if inst.is_a("IfcOpeningElement"):
|
||||||
|
building_element = self.get_voided_element(inst)
|
||||||
|
else:
|
||||||
|
building_element = None
|
||||||
|
opening = self.get_filled_opening(inst)
|
||||||
|
if opening:
|
||||||
|
building_element = self.get_voided_element(opening)
|
||||||
is_pass = building_element is not None
|
is_pass = building_element is not None
|
||||||
if not is_pass:
|
if not is_pass:
|
||||||
reason = {"type": "NOVALUE"}
|
reason = {"type": "NOVALUE"}
|
||||||
@@ -551,23 +545,8 @@ class PartOf(Facet):
|
|||||||
is_pass = True
|
is_pass = True
|
||||||
if not is_pass:
|
if not is_pass:
|
||||||
reason = {"type": "ENTITY", "actual": building_element}
|
reason = {"type": "ENTITY", "actual": building_element}
|
||||||
elif self.relation == "IFCRELFILLSELEMENT":
|
|
||||||
opening = self.filled_opening(inst)
|
|
||||||
is_pass = opening is not None
|
|
||||||
if not is_pass:
|
|
||||||
reason = {"type": "NOVALUE"}
|
|
||||||
if is_pass and self.name:
|
|
||||||
is_pass = False
|
|
||||||
if opening.is_a().upper() == self.name:
|
|
||||||
if self.predefinedType:
|
|
||||||
if ifcopenshell.util.element.get_predefined_type(opening) == self.predefinedType:
|
|
||||||
is_pass = True
|
|
||||||
else:
|
|
||||||
is_pass = True
|
|
||||||
if not is_pass:
|
|
||||||
reason = {"type": "ENTITY", "actual": opening}
|
|
||||||
|
|
||||||
if self.maxOccurs == 0:
|
if self.cardinality == "prohibited":
|
||||||
return PartOfResult(not is_pass, {"type": "PROHIBITED"})
|
return PartOfResult(not is_pass, {"type": "PROHIBITED"})
|
||||||
return PartOfResult(is_pass, reason)
|
return PartOfResult(is_pass, reason)
|
||||||
|
|
||||||
@@ -605,37 +584,35 @@ class Property(Facet):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
propertySet="Property_Set",
|
propertySet="Property_Set",
|
||||||
name="PropertyName",
|
baseName="PropertyName",
|
||||||
value=None,
|
value=None,
|
||||||
datatype=None,
|
dataType=None,
|
||||||
uri=None,
|
uri=None,
|
||||||
minOccurs=None,
|
cardinality="required",
|
||||||
maxOccurs="unbounded",
|
|
||||||
instructions=None,
|
instructions=None,
|
||||||
):
|
):
|
||||||
self.parameters = [
|
self.parameters = [
|
||||||
"propertySet",
|
"propertySet",
|
||||||
"name",
|
"baseName",
|
||||||
"value",
|
"value",
|
||||||
"@datatype",
|
"@dataType",
|
||||||
"@uri",
|
"@uri",
|
||||||
"@minOccurs",
|
"@cardinality",
|
||||||
"@maxOccurs",
|
|
||||||
"@instructions",
|
"@instructions",
|
||||||
]
|
]
|
||||||
self.applicability_templates = [
|
self.applicability_templates = [
|
||||||
"Elements with {name} data of {value} in the dataset {propertySet}",
|
"Elements with {baseName} data of {value} in the dataset {propertySet}",
|
||||||
"Elements with {name} data in the dataset {propertySet}",
|
"Elements with {baseName} data in the dataset {propertySet}",
|
||||||
]
|
]
|
||||||
self.requirement_templates = [
|
self.requirement_templates = [
|
||||||
"{name} data shall be {value} and in the dataset {propertySet}",
|
"{baseName} data shall be {value} and in the dataset {propertySet}",
|
||||||
"{name} data shall be provided in the dataset {propertySet}",
|
"{baseName} data shall be provided in the dataset {propertySet}",
|
||||||
]
|
]
|
||||||
self.prohibited_templates = [
|
self.prohibited_templates = [
|
||||||
"{name} data shall not be {value} and in the dataset {propertySet}",
|
"{baseName} data shall not be {value} and in the dataset {propertySet}",
|
||||||
"{name} data shall not be provided in the dataset {propertySet}",
|
"{baseName} data shall not be provided in the dataset {propertySet}",
|
||||||
]
|
]
|
||||||
super().__init__(propertySet, name, value, datatype, uri, minOccurs, maxOccurs, instructions)
|
super().__init__(propertySet, baseName, value, dataType, uri, cardinality, instructions)
|
||||||
|
|
||||||
def filter(
|
def filter(
|
||||||
self, ifc_file: ifcopenshell.file, elements: Union[ifcopenshell.entity_instance, None]
|
self, ifc_file: ifcopenshell.file, elements: Union[ifcopenshell.entity_instance, None]
|
||||||
@@ -651,7 +628,7 @@ class Property(Facet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def __call__(self, inst, logger=None):
|
def __call__(self, inst, logger=None):
|
||||||
if self.minOccurs == 0 and self.maxOccurs != 0:
|
if self.cardinality == "optional":
|
||||||
return PropertyResult(True)
|
return PropertyResult(True)
|
||||||
|
|
||||||
if isinstance(self.propertySet, str):
|
if isinstance(self.propertySet, str):
|
||||||
@@ -671,18 +648,18 @@ class Property(Facet):
|
|||||||
props = {}
|
props = {}
|
||||||
for pset_name, pset_props in psets.items():
|
for pset_name, pset_props in psets.items():
|
||||||
props[pset_name] = {}
|
props[pset_name] = {}
|
||||||
if isinstance(self.name, str):
|
if isinstance(self.baseName, str):
|
||||||
prop = pset_props.get(self.name)
|
prop = pset_props.get(self.baseName)
|
||||||
if prop == "UNKNOWN" and [
|
if prop == "UNKNOWN" and [
|
||||||
p
|
p
|
||||||
for p in self.get_properties(inst.wrapped_data.file.by_id(pset_props["id"]))
|
for p in self.get_properties(inst.wrapped_data.file.by_id(pset_props["id"]))
|
||||||
if p.Name == self.name
|
if p.Name == self.baseName
|
||||||
][0].NominalValue.is_a("IfcLogical"):
|
][0].NominalValue.is_a("IfcLogical"):
|
||||||
pass
|
pass
|
||||||
elif prop is not None and prop != "":
|
elif prop is not None and prop != "":
|
||||||
props[pset_name][self.name] = prop
|
props[pset_name][self.baseName] = prop
|
||||||
else:
|
else:
|
||||||
props[pset_name] = {k: v for k, v in pset_props.items() if k == self.name}
|
props[pset_name] = {k: v for k, v in pset_props.items() if k == self.baseName}
|
||||||
|
|
||||||
if not bool(props[pset_name]):
|
if not bool(props[pset_name]):
|
||||||
is_pass = False
|
is_pass = False
|
||||||
@@ -701,9 +678,9 @@ class Property(Facet):
|
|||||||
elif prop_entity.is_a("IfcPropertySingleValue"):
|
elif prop_entity.is_a("IfcPropertySingleValue"):
|
||||||
data_type = prop_entity.NominalValue.is_a()
|
data_type = prop_entity.NominalValue.is_a()
|
||||||
|
|
||||||
if data_type.lower() != self.datatype.lower():
|
if self.dataType and data_type.lower() != self.dataType.lower():
|
||||||
is_pass = False
|
is_pass = False
|
||||||
reason = {"type": "DATATYPE", "actual": data_type, "datatype": self.datatype}
|
reason = {"type": "DATATYPE", "actual": data_type, "dataType": self.dataType}
|
||||||
break
|
break
|
||||||
|
|
||||||
unit = ifcopenshell.util.unit.get_property_unit(prop_entity, inst.wrapped_data.file)
|
unit = ifcopenshell.util.unit.get_property_unit(prop_entity, inst.wrapped_data.file)
|
||||||
@@ -720,9 +697,9 @@ class Property(Facet):
|
|||||||
prop_schema = prop_entity.wrapped_data.declaration().as_entity()
|
prop_schema = prop_entity.wrapped_data.declaration().as_entity()
|
||||||
data_type = prop_schema.attribute_by_index(3).type_of_attribute().declared_type().name()
|
data_type = prop_schema.attribute_by_index(3).type_of_attribute().declared_type().name()
|
||||||
|
|
||||||
if data_type.lower() != self.datatype.lower():
|
if self.dataType and data_type.lower() != self.dataType.lower():
|
||||||
is_pass = False
|
is_pass = False
|
||||||
reason = {"type": "DATATYPE", "actual": data_type, "datatype": self.datatype}
|
reason = {"type": "DATATYPE", "actual": data_type, "dataType": self.dataType}
|
||||||
break
|
break
|
||||||
|
|
||||||
unit = ifcopenshell.util.unit.get_property_unit(prop_entity, inst.wrapped_data.file)
|
unit = ifcopenshell.util.unit.get_property_unit(prop_entity, inst.wrapped_data.file)
|
||||||
@@ -740,9 +717,9 @@ class Property(Facet):
|
|||||||
reason = {"type": "NOVALUE"}
|
reason = {"type": "NOVALUE"}
|
||||||
break
|
break
|
||||||
data_type = prop_entity.EnumerationValues[0].is_a()
|
data_type = prop_entity.EnumerationValues[0].is_a()
|
||||||
if data_type.lower() != self.datatype.lower():
|
if self.dataType and data_type.lower() != self.dataType.lower():
|
||||||
is_pass = False
|
is_pass = False
|
||||||
reason = {"type": "DATATYPE", "actual": data_type, "datatype": self.datatype}
|
reason = {"type": "DATATYPE", "actual": data_type, "dataType": self.dataType}
|
||||||
break
|
break
|
||||||
elif prop_entity.is_a("IfcPropertyListValue"):
|
elif prop_entity.is_a("IfcPropertyListValue"):
|
||||||
if not prop_entity.ListValues:
|
if not prop_entity.ListValues:
|
||||||
@@ -750,9 +727,9 @@ class Property(Facet):
|
|||||||
reason = {"type": "NOVALUE"}
|
reason = {"type": "NOVALUE"}
|
||||||
break
|
break
|
||||||
data_type = prop_entity.ListValues[0].is_a()
|
data_type = prop_entity.ListValues[0].is_a()
|
||||||
if data_type.lower() != self.datatype.lower():
|
if self.dataType and data_type.lower() != self.dataType.lower():
|
||||||
is_pass = False
|
is_pass = False
|
||||||
reason = {"type": "DATATYPE", "actual": data_type, "datatype": self.datatype}
|
reason = {"type": "DATATYPE", "actual": data_type, "dataType": self.dataType}
|
||||||
break
|
break
|
||||||
unit = ifcopenshell.util.unit.get_property_unit(prop_entity, inst.wrapped_data.file)
|
unit = ifcopenshell.util.unit.get_property_unit(prop_entity, inst.wrapped_data.file)
|
||||||
if unit:
|
if unit:
|
||||||
@@ -773,9 +750,9 @@ class Property(Facet):
|
|||||||
if value is not None:
|
if value is not None:
|
||||||
data_type = value.is_a()
|
data_type = value.is_a()
|
||||||
values.append(value.wrappedValue)
|
values.append(value.wrappedValue)
|
||||||
if data_type.lower() != self.datatype.lower():
|
if self.dataType and data_type.lower() != self.dataType.lower():
|
||||||
is_pass = False
|
is_pass = False
|
||||||
reason = {"type": "DATATYPE", "actual": data_type, "datatype": self.datatype}
|
reason = {"type": "DATATYPE", "actual": data_type, "dataType": self.dataType}
|
||||||
break
|
break
|
||||||
unit = ifcopenshell.util.unit.get_property_unit(prop_entity, inst.wrapped_data.file)
|
unit = ifcopenshell.util.unit.get_property_unit(prop_entity, inst.wrapped_data.file)
|
||||||
if unit:
|
if unit:
|
||||||
@@ -798,7 +775,7 @@ class Property(Facet):
|
|||||||
if not column_values:
|
if not column_values:
|
||||||
continue
|
continue
|
||||||
data_type = column_values[0].is_a()
|
data_type = column_values[0].is_a()
|
||||||
if data_type.lower() == self.datatype.lower():
|
if self.dataType and data_type.lower() == self.dataType.lower():
|
||||||
column_values = [v.wrappedValue for v in column_values]
|
column_values = [v.wrappedValue for v in column_values]
|
||||||
unit = units[f"{attribute}Unit"]
|
unit = units[f"{attribute}Unit"]
|
||||||
if unit:
|
if unit:
|
||||||
@@ -815,7 +792,7 @@ class Property(Facet):
|
|||||||
values.extend(column_values)
|
values.extend(column_values)
|
||||||
if not values:
|
if not values:
|
||||||
is_pass = False
|
is_pass = False
|
||||||
reason = {"type": "DATATYPE", "actual": data_type, "datatype": self.datatype}
|
reason = {"type": "DATATYPE", "actual": data_type, "dataType": self.dataType}
|
||||||
break
|
break
|
||||||
props[pset_name][prop_entity.Name] = values
|
props[pset_name][prop_entity.Name] = values
|
||||||
else:
|
else:
|
||||||
@@ -868,7 +845,7 @@ class Property(Facet):
|
|||||||
reason = {"type": "VALUE", "actual": value}
|
reason = {"type": "VALUE", "actual": value}
|
||||||
break
|
break
|
||||||
|
|
||||||
if self.maxOccurs == 0:
|
if self.cardinality == "prohibited":
|
||||||
return PropertyResult(not is_pass, {"type": "PROHIBITED"})
|
return PropertyResult(not is_pass, {"type": "PROHIBITED"})
|
||||||
return PropertyResult(is_pass, reason)
|
return PropertyResult(is_pass, reason)
|
||||||
|
|
||||||
@@ -888,8 +865,8 @@ class Property(Facet):
|
|||||||
|
|
||||||
|
|
||||||
class Material(Facet):
|
class Material(Facet):
|
||||||
def __init__(self, value=None, uri=None, minOccurs=None, maxOccurs="unbounded", instructions=None):
|
def __init__(self, value=None, uri=None, cardinality="required", instructions=None):
|
||||||
self.parameters = ["value", "@uri", "@minOccurs", "@maxOccurs", "@instructions"]
|
self.parameters = ["value", "@uri", "@cardinality", "@instructions"]
|
||||||
self.applicability_templates = [
|
self.applicability_templates = [
|
||||||
"All data with a {value} material",
|
"All data with a {value} material",
|
||||||
"All data with a material",
|
"All data with a material",
|
||||||
@@ -902,7 +879,7 @@ class Material(Facet):
|
|||||||
"Shall not have a material of {value}",
|
"Shall not have a material of {value}",
|
||||||
"Shall not have a material",
|
"Shall not have a material",
|
||||||
]
|
]
|
||||||
super().__init__(value, uri, minOccurs, maxOccurs, instructions)
|
super().__init__(value, uri, cardinality, instructions)
|
||||||
|
|
||||||
def filter(
|
def filter(
|
||||||
self, ifc_file: ifcopenshell.file, elements: Union[ifcopenshell.entity_instance, None]
|
self, ifc_file: ifcopenshell.file, elements: Union[ifcopenshell.entity_instance, None]
|
||||||
@@ -912,7 +889,7 @@ class Material(Facet):
|
|||||||
return ifc_file.by_type("IfcObjectDefinition")
|
return ifc_file.by_type("IfcObjectDefinition")
|
||||||
|
|
||||||
def __call__(self, inst, logger=None):
|
def __call__(self, inst, logger=None):
|
||||||
if self.minOccurs == 0 and self.maxOccurs != 0:
|
if self.cardinality == "optional":
|
||||||
return MaterialResult(True)
|
return MaterialResult(True)
|
||||||
|
|
||||||
material = ifcopenshell.util.element.get_material(inst, should_skip_usage=True)
|
material = ifcopenshell.util.element.get_material(inst, should_skip_usage=True)
|
||||||
@@ -963,7 +940,7 @@ class Material(Facet):
|
|||||||
if not is_pass:
|
if not is_pass:
|
||||||
reason = {"type": "VALUE", "actual": values}
|
reason = {"type": "VALUE", "actual": values}
|
||||||
|
|
||||||
if self.maxOccurs == 0:
|
if self.cardinality == "prohibited":
|
||||||
return MaterialResult(not is_pass, {"type": "PROHIBITED"})
|
return MaterialResult(not is_pass, {"type": "PROHIBITED"})
|
||||||
return MaterialResult(is_pass, reason)
|
return MaterialResult(is_pass, reason)
|
||||||
|
|
||||||
@@ -1108,7 +1085,7 @@ class PropertyResult(Result):
|
|||||||
elif self.reason["type"] == "NOVALUE":
|
elif self.reason["type"] == "NOVALUE":
|
||||||
return "The property set does not contain the required property"
|
return "The property set does not contain the required property"
|
||||||
elif self.reason["type"] == "DATATYPE":
|
elif self.reason["type"] == "DATATYPE":
|
||||||
return f"The property's data type \"{str(self.reason['actual'])}\" does not match the required data type of \"{str(self.reason['datatype'])}\""
|
return f"The property's data type \"{str(self.reason['actual'])}\" does not match the required data type of \"{str(self.reason['dataType'])}\""
|
||||||
elif self.reason["type"] == "VALUE":
|
elif self.reason["type"] == "VALUE":
|
||||||
if isinstance(self.reason["actual"], list):
|
if isinstance(self.reason["actual"], list):
|
||||||
if len(self.reason["actual"]) == 1:
|
if len(self.reason["actual"]) == 1:
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ class Ids:
|
|||||||
"@xmlns": "http://standards.buildingsmart.org/IDS",
|
"@xmlns": "http://standards.buildingsmart.org/IDS",
|
||||||
"@xmlns:xs": "http://www.w3.org/2001/XMLSchema",
|
"@xmlns:xs": "http://www.w3.org/2001/XMLSchema",
|
||||||
"@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
|
"@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
|
||||||
"@xsi:schemaLocation": "http://standards.buildingsmart.org/IDS http://standards.buildingsmart.org/IDS/0.9.6/ids.xsd",
|
"@xsi:schemaLocation": "http://standards.buildingsmart.org/IDS http://standards.buildingsmart.org/IDS/0.9.7/ids.xsd",
|
||||||
"info": info,
|
"info": info,
|
||||||
"specifications": {"specification": []},
|
"specifications": {"specification": []},
|
||||||
}
|
}
|
||||||
@@ -164,7 +164,7 @@ class Specification:
|
|||||||
"applicability": {},
|
"applicability": {},
|
||||||
"requirements": {},
|
"requirements": {},
|
||||||
}
|
}
|
||||||
for attribute in ["identifier", "description", "instructions", "minOccurs", "maxOccurs"]:
|
for attribute in ["identifier", "description", "instructions"]:
|
||||||
value = getattr(self, attribute)
|
value = getattr(self, attribute)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
results[f"@{attribute}"] = value
|
results[f"@{attribute}"] = value
|
||||||
@@ -181,20 +181,25 @@ class Specification:
|
|||||||
for facet_type in ("entity", "partOf", "classification", "attribute", "property", "material"):
|
for facet_type in ("entity", "partOf", "classification", "attribute", "property", "material"):
|
||||||
if facet_type in facets:
|
if facet_type in facets:
|
||||||
results[clause_type][facet_type] = facets[facet_type]
|
results[clause_type][facet_type] = facets[facet_type]
|
||||||
|
if clause_type == "applicability":
|
||||||
|
for attribute in ["minOccurs", "maxOccurs"]:
|
||||||
|
value = getattr(self, attribute)
|
||||||
|
if value is not None:
|
||||||
|
results[clause_type][f"@{attribute}"] = value
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def parse(self, ids_dict):
|
def parse(self, ids_dict):
|
||||||
self.name = ids_dict.get("@name", "")
|
self.name = ids_dict.get("@name", "")
|
||||||
self.description = ids_dict.get("@description", "")
|
self.description = ids_dict.get("@description", "")
|
||||||
self.instructions = ids_dict.get("@instructions", "")
|
self.instructions = ids_dict.get("@instructions", "")
|
||||||
self.minOccurs = ids_dict["@minOccurs"]
|
self.minOccurs = ids_dict.get("applicability", {}).get("@minOccurs", 0)
|
||||||
self.maxOccurs = ids_dict["@maxOccurs"]
|
self.maxOccurs = ids_dict.get("applicability", {}).get("@minOccurs", "unbounded")
|
||||||
self.ifcVersion = ids_dict["@ifcVersion"]
|
self.ifcVersion = ids_dict["@ifcVersion"]
|
||||||
self.applicability = (
|
self.applicability = (
|
||||||
self.parse_clause(ids_dict["applicability"]) if ids_dict.get("applicability") is not None else []
|
self.parse_clause(ids_dict["applicability"]) if ids_dict.get("applicability", None) is not None else []
|
||||||
)
|
)
|
||||||
self.requirements = (
|
self.requirements = (
|
||||||
self.parse_clause(ids_dict["requirements"]) if ids_dict.get("requirements") is not None else []
|
self.parse_clause(ids_dict["requirements"]) if ids_dict.get("requirements", None) is not None else []
|
||||||
)
|
)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@@ -243,21 +248,17 @@ class Specification:
|
|||||||
self.applicable_entities.append(element)
|
self.applicable_entities.append(element)
|
||||||
for facet in self.requirements:
|
for facet in self.requirements:
|
||||||
result = facet(element)
|
result = facet(element)
|
||||||
if self.maxOccurs == 0:
|
if not bool(result):
|
||||||
prohibited = bool(result)
|
|
||||||
else:
|
|
||||||
prohibited = not bool(result)
|
|
||||||
if prohibited:
|
|
||||||
self.failed_entities.add(element)
|
self.failed_entities.add(element)
|
||||||
facet.failed_entities.append(element)
|
facet.failed_entities.append(element)
|
||||||
facet.failed_reasons.append(str(result))
|
facet.failed_reasons.append(str(result))
|
||||||
|
|
||||||
for facet in self.requirements:
|
for facet in self.requirements:
|
||||||
if facet.minOccurs != 0:
|
if facet.cardinality == "required":
|
||||||
facet.status = not bool(facet.failed_entities)
|
facet.status = not bool(facet.failed_entities)
|
||||||
elif facet.minOccurs == 0 and facet.maxOccurs != 0:
|
elif facet.cardinality == "optional":
|
||||||
facet.status = True
|
facet.status = True
|
||||||
elif facet.maxOccurs == 0:
|
elif facet.cardinality == "prohibited":
|
||||||
facet.status = bool(facet.failed_entities)
|
facet.status = bool(facet.failed_entities)
|
||||||
|
|
||||||
self.status = True
|
self.status = True
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- June 20, 2023 - DRAFT -->
|
<!-- Draft - Do not use in production -->
|
||||||
<xs:schema xmlns:ids="http://standards.buildingsmart.org/IDS" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:altova="http://www.altova.com/xml-schema-extensions" targetNamespace="http://standards.buildingsmart.org/IDS" elementFormDefault="qualified" attributeFormDefault="unqualified" version="0.9.6">
|
<xs:schema xmlns:ids="http://standards.buildingsmart.org/IDS" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:altova="http://www.altova.com/xml-schema-extensions" targetNamespace="http://standards.buildingsmart.org/IDS" elementFormDefault="qualified" attributeFormDefault="unqualified" version="0.9.7">
|
||||||
<xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/>
|
<xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/>
|
||||||
<xs:import namespace="http://www.w3.org/2001/XMLSchema" schemaLocation="http://www.w3.org/2001/XMLSchema.xsd"/>
|
<xs:import namespace="http://www.w3.org/2001/XMLSchema" schemaLocation="http://www.w3.org/2001/XMLSchema.xsd"/>
|
||||||
<xs:import namespace="http://www.w3.org/2001/XMLSchema-instance" schemaLocation="http://www.w3.org/2001/XMLSchema-instance"/>
|
<xs:import namespace="http://www.w3.org/2001/XMLSchema-instance" schemaLocation="http://www.w3.org/2001/XMLSchema-instance"/>
|
||||||
@@ -40,20 +40,20 @@
|
|||||||
<xs:choice minOccurs="1">
|
<xs:choice minOccurs="1">
|
||||||
<!-- place for potential additional rules for idsValue -->
|
<!-- place for potential additional rules for idsValue -->
|
||||||
<xs:element name="simpleValue" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
<xs:element name="simpleValue" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||||
<xs:element ref="xs:restriction" minOccurs="1" maxOccurs="unbounded"/>
|
<xs:element ref="xs:restriction" minOccurs="1" maxOccurs="1"/>
|
||||||
</xs:choice>
|
</xs:choice>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
<xs:complexType name="classificationType">
|
<xs:complexType name="classificationType">
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element name="value" type="ids:idsValue" minOccurs="0"/>
|
<xs:element name="value" type="ids:idsValue" minOccurs="0"/>
|
||||||
<xs:element name="system" type="ids:idsValue" minOccurs="0"/>
|
<xs:element name="system" type="ids:idsValue" minOccurs="1"/>
|
||||||
</xs:sequence>
|
</xs:sequence>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
<xs:complexType name="partOfType">
|
<xs:complexType name="partOfType">
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element name="entity" type="ids:entityType" minOccurs="1"/>
|
<xs:element name="entity" type="ids:entityType" minOccurs="1"/>
|
||||||
</xs:sequence>
|
</xs:sequence>
|
||||||
<xs:attribute name="relation" type="ids:relations"/>
|
<xs:attribute name="relation" type="ids:relations" use="optional" />
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
<xs:complexType name="applicabilityType">
|
<xs:complexType name="applicabilityType">
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
@@ -62,26 +62,53 @@
|
|||||||
<xs:element name="classification" type="ids:classificationType" minOccurs="0" maxOccurs="unbounded"/>
|
<xs:element name="classification" type="ids:classificationType" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
<xs:element name="attribute" type="ids:attributeType" minOccurs="0" maxOccurs="unbounded"/>
|
<xs:element name="attribute" type="ids:attributeType" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
<xs:element name="property" type="ids:propertyType" minOccurs="0" maxOccurs="unbounded"/>
|
<xs:element name="property" type="ids:propertyType" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
<xs:element name="material" type="ids:materialType" minOccurs="0"/>
|
<xs:element name="material" type="ids:materialType" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
</xs:sequence>
|
</xs:sequence>
|
||||||
|
<!-- Please note there is an implementation agreement on the use of minOccurs and maxOccurs.
|
||||||
|
Valid values are:
|
||||||
|
a. 0 to unbounded, meaning Optional
|
||||||
|
b. 1 to unbounded, meaning Required
|
||||||
|
c. 0 to 0, meaning Prohibited
|
||||||
|
-->
|
||||||
|
<xs:attributeGroup ref="xs:occurs"/>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
<xs:complexType name="propertyType">
|
<xs:complexType name="propertyType">
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element name="propertySet" type="ids:idsValue"/>
|
<xs:element name="propertySet" type="ids:idsValue"/>
|
||||||
<xs:element name="name" type="ids:idsValue"/>
|
<xs:element name="baseName" type="ids:idsValue">
|
||||||
<xs:element name="value" type="ids:idsValue" minOccurs="0"/>
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
the moniker 'baseName' is chosen to clarify that the data needs to reference the property name as stored in the IFC file,
|
||||||
|
which might differ from the multiple language-dependent presentations (e.g. 'FireRating' vs. 'Fire rating').
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="value" type="ids:idsValue" minOccurs="0">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
Depending on the dataType attribute, values are expressed in the default unit documented at
|
||||||
|
https://github.com/buildingSMART/IDS/blob/master/Documentation/units.md, and unit conversion might be required.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:element>
|
||||||
</xs:sequence>
|
</xs:sequence>
|
||||||
<xs:attribute name="datatype" use="required">
|
<xs:attribute name="dataType" type="ids:upperCaseName" use="optional">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>This is the name of an IFC Defined Type. See the full list for IFC 4 on https://standards.buildingsmart.org/IFC/RELEASE/IFC4/ADD2_TC1/HTML/link/alphabeticalorder-defined-types.htm Documentation and default units on https://github.com/buildingSMART/IDS/blob/master/Documentation/units.md</xs:documentation>
|
<xs:documentation>This is the name of an IFC Defined Type, all uppercase.</xs:documentation>
|
||||||
</xs:annotation>
|
</xs:annotation>
|
||||||
<!-- renamed 'measure' to data type to better represent reality -->
|
|
||||||
</xs:attribute>
|
</xs:attribute>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
<xs:complexType name="attributeType">
|
<xs:complexType name="attributeType">
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element name="name" type="ids:idsValue"/>
|
<xs:element name="name" type="ids:idsValue"/>
|
||||||
<xs:element name="value" type="ids:idsValue" minOccurs="0"/>
|
<xs:element name="value" type="ids:idsValue" minOccurs="0">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
Depending on the IFC type of the attribute, values are expressed in the default unit documented at
|
||||||
|
https://github.com/buildingSMART/IDS/blob/master/Documentation/units.md, and unit conversion might be required.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:element>
|
||||||
</xs:sequence>
|
</xs:sequence>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
<xs:complexType name="materialType">
|
<xs:complexType name="materialType">
|
||||||
@@ -98,6 +125,13 @@
|
|||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:complexContent>
|
<xs:complexContent>
|
||||||
<xs:extension base="ids:entityType">
|
<xs:extension base="ids:entityType">
|
||||||
|
<!--
|
||||||
|
Contrary to other requirements facet extensions, cardinality is not available in the entityType facet when used for requirements.
|
||||||
|
Its cardinality state is always considered to be "required".
|
||||||
|
Constraining the acceptable values is achieved by specifying criteria via with xs:Enumeration and xs:Pattern, rather than the negative form.
|
||||||
|
This is possible because the list of options is finite and mandated by the IFC schema, so prohibited constraints are superfluous.
|
||||||
|
This choice allows for improved user experience in the editors.
|
||||||
|
-->
|
||||||
<xs:attribute name="instructions" type="xs:string" use="optional">
|
<xs:attribute name="instructions" type="xs:string" use="optional">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
|
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
|
||||||
@@ -111,7 +145,7 @@
|
|||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:complexContent>
|
<xs:complexContent>
|
||||||
<xs:extension base="ids:partOfType">
|
<xs:extension base="ids:partOfType">
|
||||||
<xs:attributeGroup ref="xs:occurs"/>
|
<xs:attribute name="cardinality" type="ids:simpleCardinality" use="optional" default="required"/>
|
||||||
<xs:attribute name="instructions" type="xs:string" use="optional">
|
<xs:attribute name="instructions" type="xs:string" use="optional">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
|
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
|
||||||
@@ -126,7 +160,7 @@
|
|||||||
<xs:complexContent>
|
<xs:complexContent>
|
||||||
<xs:extension base="ids:classificationType">
|
<xs:extension base="ids:classificationType">
|
||||||
<xs:attribute name="uri" type="xs:anyURI" use="optional"/>
|
<xs:attribute name="uri" type="xs:anyURI" use="optional"/>
|
||||||
<xs:attributeGroup ref="xs:occurs"/>
|
<xs:attribute name="cardinality" type="ids:conditionalCardinality" use="optional" default="required"/>
|
||||||
<xs:attribute name="instructions" type="xs:string" use="optional">
|
<xs:attribute name="instructions" type="xs:string" use="optional">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
|
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
|
||||||
@@ -140,6 +174,7 @@
|
|||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:complexContent>
|
<xs:complexContent>
|
||||||
<xs:extension base="ids:attributeType">
|
<xs:extension base="ids:attributeType">
|
||||||
|
<xs:attribute name="cardinality" type="ids:conditionalCardinality" use="optional" default="required"/>
|
||||||
<xs:attribute name="instructions" type="xs:string" use="optional">
|
<xs:attribute name="instructions" type="xs:string" use="optional">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
|
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
|
||||||
@@ -154,7 +189,7 @@
|
|||||||
<xs:complexContent>
|
<xs:complexContent>
|
||||||
<xs:extension base="ids:propertyType">
|
<xs:extension base="ids:propertyType">
|
||||||
<xs:attribute name="uri" type="xs:anyURI" use="optional"/>
|
<xs:attribute name="uri" type="xs:anyURI" use="optional"/>
|
||||||
<xs:attributeGroup ref="xs:occurs"/>
|
<xs:attribute name="cardinality" type="ids:conditionalCardinality" use="optional" default="required"/>
|
||||||
<xs:attribute name="instructions" type="xs:string" use="optional">
|
<xs:attribute name="instructions" type="xs:string" use="optional">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
|
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
|
||||||
@@ -164,12 +199,12 @@
|
|||||||
</xs:complexContent>
|
</xs:complexContent>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
<xs:element name="material" minOccurs="0">
|
<xs:element name="material" minOccurs="0" maxOccurs="unbounded">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:complexContent>
|
<xs:complexContent>
|
||||||
<xs:extension base="ids:materialType">
|
<xs:extension base="ids:materialType">
|
||||||
<xs:attribute name="uri" type="xs:anyURI" use="optional"/>
|
<xs:attribute name="uri" type="xs:anyURI" use="optional"/>
|
||||||
<xs:attributeGroup ref="xs:occurs"/>
|
<xs:attribute name="cardinality" type="ids:conditionalCardinality" use="optional" default="required"/>
|
||||||
<xs:attribute name="instructions" type="xs:string" use="optional">
|
<xs:attribute name="instructions" type="xs:string" use="optional">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
|
<xs:documentation>Author of the IDS can leave instructions for the authors of the IFC. This text could/should be displayed in the BIM/IFC authoring tool.</xs:documentation>
|
||||||
@@ -195,7 +230,6 @@
|
|||||||
</xs:element>
|
</xs:element>
|
||||||
</xs:sequence>
|
</xs:sequence>
|
||||||
<xs:attribute name="name" type="xs:string" use="required"/>
|
<xs:attribute name="name" type="xs:string" use="required"/>
|
||||||
<xs:attributeGroup ref="xs:occurs"/>
|
|
||||||
<xs:attribute name="ifcVersion" use="required">
|
<xs:attribute name="ifcVersion" use="required">
|
||||||
<xs:simpleType>
|
<xs:simpleType>
|
||||||
<xs:list>
|
<xs:list>
|
||||||
@@ -210,7 +244,7 @@
|
|||||||
</xs:list>
|
</xs:list>
|
||||||
</xs:simpleType>
|
</xs:simpleType>
|
||||||
</xs:attribute>
|
</xs:attribute>
|
||||||
<xs:attribute name="identifier" type="xs:string">
|
<xs:attribute name="identifier" type="xs:string" use="optional">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>Author of the IDS can provide an identifier to the specification. This is intended to be a machine readable identifier. Beware: because of the possibility to combine different 'specification' elements from several ids files this cannot be enforced/assumed as (global) unique.</xs:documentation>
|
<xs:documentation>Author of the IDS can provide an identifier to the specification. This is intended to be a machine readable identifier. Beware: because of the possibility to combine different 'specification' elements from several ids files this cannot be enforced/assumed as (global) unique.</xs:documentation>
|
||||||
</xs:annotation>
|
</xs:annotation>
|
||||||
@@ -229,12 +263,30 @@
|
|||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
<xs:simpleType name="relations">
|
<xs:simpleType name="relations">
|
||||||
<xs:restriction base="xs:string">
|
<xs:restriction base="xs:string">
|
||||||
<xs:enumeration value="IFCRELAGGREGATES"/>
|
<xs:enumeration value="IFCRELAGGREGATES"/>
|
||||||
<xs:enumeration value="IFCRELASSIGNSTOGROUP"/>
|
<xs:enumeration value="IFCRELASSIGNSTOGROUP"/>
|
||||||
<xs:enumeration value="IFCRELCONTAINEDINSPATIALSTRUCTURE"/>
|
<xs:enumeration value="IFCRELCONTAINEDINSPATIALSTRUCTURE"/>
|
||||||
<xs:enumeration value="IFCRELNESTS"/>
|
<xs:enumeration value="IFCRELNESTS"/>
|
||||||
<xs:enumeration value="IFCRELVOIDSELEMENT"/>
|
<xs:enumeration value="IFCRELVOIDSELEMENT IFCRELFILLSELEMENT"/>
|
||||||
<xs:enumeration value="IFCRELFILLSELEMENT"/>
|
|
||||||
</xs:restriction>
|
</xs:restriction>
|
||||||
</xs:simpleType>
|
</xs:simpleType>
|
||||||
</xs:schema>
|
<xs:simpleType name="upperCaseName">
|
||||||
|
<xs:restriction base="xs:normalizedString">
|
||||||
|
<xs:pattern value="[A-Z]+"/>
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
<xs:simpleType name="simpleCardinality">
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:enumeration value="required"/>
|
||||||
|
<xs:enumeration value="prohibited"/>
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
<xs:simpleType name="conditionalCardinality">
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:enumeration value="required"/>
|
||||||
|
<xs:enumeration value="prohibited"/>
|
||||||
|
<xs:enumeration value="optional"/>
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
|
</xs:schema>
|
||||||
|
|||||||
+112
-125
@@ -37,9 +37,9 @@ def run(name, *, facet, inst, expected):
|
|||||||
class TestEntity:
|
class TestEntity:
|
||||||
def test_creating_an_entity_facet(self):
|
def test_creating_an_entity_facet(self):
|
||||||
facet = Entity(name="IfcName")
|
facet = Entity(name="IfcName")
|
||||||
assert facet.asdict() == {"name": {"simpleValue": "IfcName"}}
|
assert facet.asdict("applicability") == {"name": {"simpleValue": "IfcName"}}
|
||||||
facet = Entity(name="IfcName", predefinedType="predefinedType", instructions="instructions")
|
facet = Entity(name="IfcName", predefinedType="predefinedType", instructions="instructions")
|
||||||
assert facet.asdict() == {
|
assert facet.asdict("requirement") == {
|
||||||
"name": {"simpleValue": "IfcName"},
|
"name": {"simpleValue": "IfcName"},
|
||||||
"predefinedType": {"simpleValue": "predefinedType"},
|
"predefinedType": {"simpleValue": "predefinedType"},
|
||||||
"@instructions": "instructions",
|
"@instructions": "instructions",
|
||||||
@@ -223,17 +223,16 @@ class TestEntity:
|
|||||||
class TestAttribute:
|
class TestAttribute:
|
||||||
def test_creating_an_attribute_facet(self):
|
def test_creating_an_attribute_facet(self):
|
||||||
attribute = Attribute(name="name")
|
attribute = Attribute(name="name")
|
||||||
assert attribute.asdict() == {"name": {"simpleValue": "name"}}
|
assert attribute.asdict("applicability") == {"name": {"simpleValue": "name"}}
|
||||||
attribute = Attribute(name="name", value="value")
|
attribute = Attribute(name="name", value="value")
|
||||||
assert attribute.asdict() == {"name": {"simpleValue": "name"}, "value": {"simpleValue": "value"}}
|
assert attribute.asdict("applicability") == {"name": {"simpleValue": "name"}, "value": {"simpleValue": "value"}}
|
||||||
attribute = Attribute(
|
attribute = Attribute(
|
||||||
name="name", value="value", minOccurs="0", maxOccurs="unbounded", instructions="instructions"
|
name="name", value="value", cardinality="required", instructions="instructions"
|
||||||
)
|
)
|
||||||
assert attribute.asdict() == {
|
assert attribute.asdict("requirement") == {
|
||||||
"name": {"simpleValue": "name"},
|
"name": {"simpleValue": "name"},
|
||||||
"value": {"simpleValue": "value"},
|
"value": {"simpleValue": "value"},
|
||||||
"@minOccurs": "0",
|
"@cardinality": "required",
|
||||||
"@maxOccurs": "unbounded",
|
|
||||||
"@instructions": "instructions",
|
"@instructions": "instructions",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,12 +257,12 @@ class TestAttribute:
|
|||||||
element = ifc.createIfcWall(Name="Foobar")
|
element = ifc.createIfcWall(Name="Foobar")
|
||||||
run("A required facet checks all parameters as normal", facet=facet, inst=element, expected=True)
|
run("A required facet checks all parameters as normal", facet=facet, inst=element, expected=True)
|
||||||
|
|
||||||
# facet = Attribute(name="Name", minOccurs=0, maxOccurs=0)
|
facet = Attribute(name="Name", cardinality="prohibited")
|
||||||
# run("A prohibited facet returns the opposite of a required facet", facet=facet, inst=element, expected=False)
|
run("A prohibited facet returns the opposite of a required facet", facet=facet, inst=element, expected=False)
|
||||||
# facet = Attribute(name="Name", minOccurs=0)
|
facet = Attribute(name="Name", cardinality="optional")
|
||||||
# run("An optional facet always passes regardless of outcome 1/2", facet=facet, inst=element, expected=True)
|
run("An optional facet always passes regardless of outcome 1/2", facet=facet, inst=element, expected=True)
|
||||||
# facet = Attribute(name="Rabbit", minOccurs=0)
|
facet = Attribute(name="Rabbit", cardinality="optional")
|
||||||
# run("An optional facet always passes regardless of outcome 2/2", facet=facet, inst=element, expected=True)
|
run("An optional facet always passes regardless of outcome 2/2", facet=facet, inst=element, expected=True)
|
||||||
|
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
facet = Attribute(name="Name")
|
facet = Attribute(name="Name")
|
||||||
@@ -668,26 +667,22 @@ class TestAttribute:
|
|||||||
|
|
||||||
class TestClassification:
|
class TestClassification:
|
||||||
def test_creating_a_classification_facet(self):
|
def test_creating_a_classification_facet(self):
|
||||||
facet = Classification()
|
facet = Classification(system="system")
|
||||||
assert facet.asdict() == {
|
assert facet.asdict("requirement") == {"system": {"simpleValue": "system"}, "@cardinality": "required" }
|
||||||
"@maxOccurs": "unbounded"
|
|
||||||
}
|
|
||||||
facet = Classification(value="value", system="system")
|
facet = Classification(value="value", system="system")
|
||||||
assert facet.asdict() == {"value": {"simpleValue": "value"}, "system": {"simpleValue": "system"}, "@maxOccurs": "unbounded" }
|
assert facet.asdict("requirement") == {"value": {"simpleValue": "value"}, "system": {"simpleValue": "system"}, "@cardinality": "required" }
|
||||||
facet = Classification(
|
facet = Classification(
|
||||||
value="value",
|
value="value",
|
||||||
system="system",
|
system="system",
|
||||||
uri="https://test.com",
|
uri="https://test.com",
|
||||||
minOccurs="0",
|
cardinality="required",
|
||||||
maxOccurs="unbounded",
|
|
||||||
instructions="instructions",
|
instructions="instructions",
|
||||||
)
|
)
|
||||||
assert facet.asdict() == {
|
assert facet.asdict("requirement") == {
|
||||||
"value": {"simpleValue": "value"},
|
"value": {"simpleValue": "value"},
|
||||||
"system": {"simpleValue": "system"},
|
"system": {"simpleValue": "system"},
|
||||||
"@uri": "https://test.com",
|
"@uri": "https://test.com",
|
||||||
"@minOccurs": "0",
|
"@cardinality": "required",
|
||||||
"@maxOccurs": "unbounded",
|
|
||||||
"@instructions": "instructions",
|
"@instructions": "instructions",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -729,29 +724,29 @@ class TestClassification:
|
|||||||
"classification.add_reference", ifc, product=material, reference=ref1, classification=system_a
|
"classification.add_reference", ifc, product=material, reference=ref1, classification=system_a
|
||||||
)
|
)
|
||||||
|
|
||||||
facet = Classification()
|
facet = Classification(system="Foobar")
|
||||||
run(
|
run(
|
||||||
"A classification facet with no data matches any classification 1/2",
|
"A classification facet with no value matches any classification 1/2",
|
||||||
facet=facet,
|
facet=facet,
|
||||||
inst=element0,
|
inst=element0,
|
||||||
expected=False,
|
expected=False,
|
||||||
)
|
)
|
||||||
run(
|
run(
|
||||||
"A classification facet with no data matches any classification 2/2",
|
"A classification facet with no value matches any classification 2/2",
|
||||||
facet=facet,
|
facet=facet,
|
||||||
inst=element1,
|
inst=element1,
|
||||||
expected=True,
|
expected=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
run("A required facet checks all parameters as normal", facet=facet, inst=element1, expected=True)
|
run("A required facet checks all parameters as normal", facet=facet, inst=element1, expected=True)
|
||||||
facet = Classification(minOccurs=0, maxOccurs=0)
|
facet = Classification(system="Foobar", cardinality="prohibited")
|
||||||
run("A prohibited facet returns the opposite of a required facet", facet=facet, inst=element1, expected=False)
|
run("A prohibited facet returns the opposite of a required facet", facet=facet, inst=element1, expected=False)
|
||||||
facet = Classification(minOccurs=0)
|
facet = Classification(system="Foobar", cardinality="optional")
|
||||||
run("An optional facet always passes regardless of outcome 1/2", facet=facet, inst=element0, expected=True)
|
run("An optional facet always passes regardless of outcome 1/2", facet=facet, inst=element0, expected=True)
|
||||||
facet = Classification(minOccurs=0)
|
facet = Classification(system="Foobar", cardinality="optional")
|
||||||
run("An optional facet always passes regardless of outcome 2/2", facet=facet, inst=element1, expected=True)
|
run("An optional facet always passes regardless of outcome 2/2", facet=facet, inst=element1, expected=True)
|
||||||
|
|
||||||
facet = Classification(value="1")
|
facet = Classification(system="Foobar", value="1")
|
||||||
run(
|
run(
|
||||||
"Values should match exactly if lightweight classifications are used",
|
"Values should match exactly if lightweight classifications are used",
|
||||||
facet=facet,
|
facet=facet,
|
||||||
@@ -759,7 +754,7 @@ class TestClassification:
|
|||||||
expected=True,
|
expected=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
facet = Classification(value="2")
|
facet = Classification(system="Foobar", value="2")
|
||||||
run(
|
run(
|
||||||
"Values match subreferences if full classifications are used (e.g. EF_25_10 should match EF_25_10_25, EF_25_10_30, etc)",
|
"Values match subreferences if full classifications are used (e.g. EF_25_10 should match EF_25_10_25, EF_25_10_30, etc)",
|
||||||
facet=facet,
|
facet=facet,
|
||||||
@@ -767,7 +762,7 @@ class TestClassification:
|
|||||||
expected=True,
|
expected=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
facet = Classification(value="1")
|
facet = Classification(system="Foobar", value="1")
|
||||||
run(
|
run(
|
||||||
"Non-rooted resources that have external classification references should also pass",
|
"Non-rooted resources that have external classification references should also pass",
|
||||||
facet=facet,
|
facet=facet,
|
||||||
@@ -783,7 +778,7 @@ class TestClassification:
|
|||||||
run("Systems should match exactly 5/5", facet=facet, inst=element22, expected=True)
|
run("Systems should match exactly 5/5", facet=facet, inst=element22, expected=True)
|
||||||
|
|
||||||
restriction = Restriction(options={"pattern": "1.*"})
|
restriction = Restriction(options={"pattern": "1.*"})
|
||||||
facet = Classification(value=restriction)
|
facet = Classification(system="Foobar", value=restriction)
|
||||||
run("Restrictions can be used for values 1/3", facet=facet, inst=element1, expected=True)
|
run("Restrictions can be used for values 1/3", facet=facet, inst=element1, expected=True)
|
||||||
run("Restrictions can be used for values 2/3", facet=facet, inst=element11, expected=True)
|
run("Restrictions can be used for values 2/3", facet=facet, inst=element11, expected=True)
|
||||||
run("Restrictions can be used for values 3/3", facet=facet, inst=element22, expected=False)
|
run("Restrictions can be used for values 3/3", facet=facet, inst=element22, expected=False)
|
||||||
@@ -824,40 +819,38 @@ class TestClassification:
|
|||||||
"classification.add_reference", ifc, product=wall_type, reference=refx, classification=system_b
|
"classification.add_reference", ifc, product=wall_type, reference=refx, classification=system_b
|
||||||
)
|
)
|
||||||
|
|
||||||
facet = Classification(value="11")
|
facet = Classification(system="Foobar", value="11")
|
||||||
run("Occurrences override the type classification per system 1/3", facet=facet, inst=wall, expected=True)
|
run("Occurrences override the type classification per system 1/3", facet=facet, inst=wall, expected=True)
|
||||||
facet = Classification(value="22")
|
facet = Classification(system="Foobar", value="22")
|
||||||
run("Occurrences override the type classification per system 2/3", facet=facet, inst=wall, expected=False)
|
run("Occurrences override the type classification per system 2/3", facet=facet, inst=wall, expected=False)
|
||||||
facet = Classification(value="X")
|
facet = Classification(system="Foobaz", value="X")
|
||||||
run("Occurrences override the type classification per system 3/3", facet=facet, inst=wall, expected=True)
|
run("Occurrences override the type classification per system 3/3", facet=facet, inst=wall, expected=True)
|
||||||
|
|
||||||
|
|
||||||
class TestProperty:
|
class TestProperty:
|
||||||
def test_creating_a_property_facet(self):
|
def test_creating_a_property_facet(self):
|
||||||
facet = Property()
|
facet = Property()
|
||||||
assert facet.asdict() == {
|
assert facet.asdict("requirement") == {
|
||||||
"propertySet": {"simpleValue": "Property_Set"},
|
"propertySet": {"simpleValue": "Property_Set"},
|
||||||
"name": {"simpleValue": "PropertyName"},
|
"baseName": {"simpleValue": "PropertyName"},
|
||||||
"@maxOccurs": "unbounded"
|
"@cardinality": "required"
|
||||||
}
|
}
|
||||||
facet = Property(
|
facet = Property(
|
||||||
propertySet="propertySet",
|
propertySet="propertySet",
|
||||||
name="name",
|
baseName="baseName",
|
||||||
value="value",
|
value="value",
|
||||||
datatype="datatype",
|
dataType="dataType",
|
||||||
uri="https://test.com",
|
uri="https://test.com",
|
||||||
minOccurs="0",
|
cardinality="required",
|
||||||
maxOccurs="unbounded",
|
|
||||||
instructions="instructions",
|
instructions="instructions",
|
||||||
)
|
)
|
||||||
assert facet.asdict() == {
|
assert facet.asdict("requirement") == {
|
||||||
"propertySet": {"simpleValue": "propertySet"},
|
"propertySet": {"simpleValue": "propertySet"},
|
||||||
"name": {"simpleValue": "name"},
|
"baseName": {"simpleValue": "baseName"},
|
||||||
"value": {"simpleValue": "value"},
|
"value": {"simpleValue": "value"},
|
||||||
"@datatype": "datatype",
|
"@dataType": "DATATYPE",
|
||||||
"@uri": "https://test.com",
|
"@uri": "https://test.com",
|
||||||
"@minOccurs": "0",
|
"@cardinality": "required",
|
||||||
"@maxOccurs": "unbounded",
|
|
||||||
"@instructions": "instructions",
|
"@instructions": "instructions",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -866,7 +859,7 @@ class TestProperty:
|
|||||||
|
|
||||||
ifc = self.setup_ifc()
|
ifc = self.setup_ifc()
|
||||||
|
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", datatype="IFCLABEL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", dataType="IFCLABEL")
|
||||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
||||||
run("Elements with no properties always fail", facet=facet, inst=element, expected=False)
|
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")
|
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar")
|
||||||
@@ -878,27 +871,27 @@ class TestProperty:
|
|||||||
run("A name check will match any property with any string value", facet=facet, inst=element, expected=True)
|
run("A name check will match any property with any string value", facet=facet, inst=element, expected=True)
|
||||||
|
|
||||||
ifc = self.setup_ifc()
|
ifc = self.setup_ifc()
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", datatype="IFCLABEL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", dataType="IFCLABEL")
|
||||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
||||||
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar")
|
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"})
|
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Bar"})
|
||||||
run("A required facet checks all parameters as normal", facet=facet, inst=element, expected=True)
|
run("A required facet checks all parameters as normal", facet=facet, inst=element, expected=True)
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", datatype="IFCLABEL", minOccurs=0, maxOccurs=0)
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", dataType="IFCLABEL", cardinality="prohibited")
|
||||||
run("A prohibited facet returns the opposite of a required facet", facet=facet, inst=element, expected=False)
|
run("A prohibited facet returns the opposite of a required facet", facet=facet, inst=element, expected=False)
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", datatype="IFCLABEL", minOccurs=0)
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", dataType="IFCLABEL", cardinality="optional")
|
||||||
run("An optional facet always passes regardless of outcome 1/2", facet=facet, inst=element, expected=True)
|
run("An optional facet always passes regardless of outcome 1/2", facet=facet, inst=element, expected=True)
|
||||||
facet = Property(propertySet="Foo_Bar", name="Bar", datatype="IFCLABEL", minOccurs=0)
|
facet = Property(propertySet="Foo_Bar", baseName="Bar", dataType="IFCLABEL", cardinality="optional")
|
||||||
run("An optional facet always passes regardless of outcome 2/2", facet=facet, inst=element, expected=True)
|
run("An optional facet always passes regardless of outcome 2/2", facet=facet, inst=element, expected=True)
|
||||||
|
|
||||||
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ""})
|
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ""})
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", datatype="IFCLOGICAL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", dataType="IFCLOGICAL")
|
||||||
run("An empty string is considered falsey and will not pass", facet=facet, inst=element, expected=False)
|
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")})
|
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcLogical("UNKNOWN")})
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", datatype="IFCDURATION")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", dataType="IFCDURATION")
|
||||||
run("A logical unknown is considered falsey and will not pass", facet=facet, inst=element, expected=False)
|
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")})
|
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)
|
run("A zero duration will pass", facet=facet, inst=element, expected=True)
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", datatype="IFCBOOLEAN")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", dataType="IFCBOOLEAN")
|
||||||
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcBoolean(True)})
|
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)
|
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})
|
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": False})
|
||||||
@@ -910,7 +903,7 @@ class TestProperty:
|
|||||||
)
|
)
|
||||||
|
|
||||||
ifc = self.setup_ifc()
|
ifc = self.setup_ifc()
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="Bar", datatype="IFCLABEL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="Bar", dataType="IFCLABEL")
|
||||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
||||||
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar")
|
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"})
|
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Bar"})
|
||||||
@@ -920,55 +913,55 @@ class TestProperty:
|
|||||||
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Baz"})
|
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)
|
run("Specifying a value fails against different values", facet=facet, inst=element, expected=False)
|
||||||
|
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="♫Don'tÄrgerhôtelЊет", datatype="IFCLABEL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="♫Don'tÄrgerhôtelЊет", dataType="IFCLABEL")
|
||||||
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "♫Don'tÄrgerhôtelЊет"})
|
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "♫Don'tÄrgerhôtelЊет"})
|
||||||
run("Non-ascii characters are treated without encoding", facet=facet, inst=element, expected=True)
|
run("Non-ascii characters are treated without encoding", facet=facet, inst=element, expected=True)
|
||||||
|
|
||||||
identifier = "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345"
|
identifier = "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345"
|
||||||
facet = Property(
|
facet = Property(
|
||||||
propertySet="Foo_Bar", name="Foo", value=identifier + "_extra_characters", datatype="IFCIDENTIFIER"
|
propertySet="Foo_Bar", baseName="Foo", value=identifier + "_extra_characters", dataType="IFCIDENTIFIER"
|
||||||
)
|
)
|
||||||
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcIdentifier(identifier)})
|
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)
|
run("IDS does not handle string truncation such as for identifiers", facet=facet, inst=element, expected=False)
|
||||||
|
|
||||||
ifc = self.setup_ifc()
|
ifc = self.setup_ifc()
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="1", datatype="IFCLABEL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="1", dataType="IFCLABEL")
|
||||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
||||||
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar")
|
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"})
|
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)
|
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", datatype="IFCINTEGER")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="42", dataType="IFCINTEGER")
|
||||||
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcInteger(42)})
|
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)
|
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.", datatype="IFCINTEGER")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="42.", dataType="IFCINTEGER")
|
||||||
run("Integer values are checked using type casting 2/4", facet=facet, inst=element, expected=True)
|
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", datatype="IFCINTEGER")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="42.0", dataType="IFCINTEGER")
|
||||||
run("Integer values are checked using type casting 3/4", facet=facet, inst=element, expected=True)
|
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", datatype="IFCINTEGER")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="42.3", dataType="IFCINTEGER")
|
||||||
run("Integer values are checked using type casting 4/4", facet=facet, inst=element, expected=False)
|
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", datatype="IFCREAL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="42", dataType="IFCREAL")
|
||||||
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcReal(42.0)})
|
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)
|
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", datatype="IFCREAL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="42.0", dataType="IFCREAL")
|
||||||
run("Real values are checked using type casting 2/3", facet=facet, inst=element, expected=True)
|
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", datatype="IFCREAL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="42.3", dataType="IFCREAL")
|
||||||
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcReal(42.3)})
|
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)
|
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", datatype="IFCREAL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="42,3", dataType="IFCREAL")
|
||||||
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcReal(42.3)})
|
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)
|
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", datatype="IFCREAL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="123,4.5", dataType="IFCREAL")
|
||||||
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcReal(1234.5)})
|
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)
|
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", datatype="IFCREAL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="1.2345e3", dataType="IFCREAL")
|
||||||
run("Only specifically formatted numbers are allowed 3/4", facet=facet, inst=element, expected=True)
|
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", datatype="IFCREAL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="1.2345E3", dataType="IFCREAL")
|
||||||
run("Only specifically formatted numbers are allowed 4/4", facet=facet, inst=element, expected=True)
|
run("Only specifically formatted numbers are allowed 4/4", facet=facet, inst=element, expected=True)
|
||||||
|
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="42.", datatype="IFCREAL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="42.", dataType="IFCREAL")
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcReal(42.0 * (1.0 + 1e-6))}
|
"pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcReal(42.0 * (1.0 + 1e-6))}
|
||||||
)
|
)
|
||||||
@@ -986,15 +979,15 @@ class TestProperty:
|
|||||||
)
|
)
|
||||||
run("Floating point numbers are compared with a 1e-6 tolerance 4/4", facet=facet, inst=element, expected=False)
|
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", datatype="IFCBOOLEAN")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="TRUE", dataType="IFCBOOLEAN")
|
||||||
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcBoolean(False)})
|
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)
|
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", datatype="IFCBOOLEAN")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="FALSE", dataType="IFCBOOLEAN")
|
||||||
run("Booleans must be specified as uppercase strings 2/3", facet=facet, inst=element, expected=True)
|
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", datatype="IFCBOOLEAN")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="False", dataType="IFCBOOLEAN")
|
||||||
run("Booleans must be specified as uppercase strings 3/3", facet=facet, inst=element, expected=False)
|
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", datatype="IFCDATE")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="2022-01-01", dataType="IFCDATE")
|
||||||
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcDate("2022-01-01")})
|
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)
|
run("Dates are treated as strings 1/2", facet=facet, inst=element, expected=True)
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
@@ -1002,7 +995,7 @@ class TestProperty:
|
|||||||
)
|
)
|
||||||
run("Dates are treated as strings 2/2", facet=facet, inst=element, expected=False)
|
run("Dates are treated as strings 2/2", facet=facet, inst=element, expected=False)
|
||||||
|
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="PT16H", datatype="IFCDURATION")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="PT16H", dataType="IFCDURATION")
|
||||||
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcDuration("PT16H")})
|
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)
|
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")})
|
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcDuration("P2D")})
|
||||||
@@ -1019,11 +1012,11 @@ class TestProperty:
|
|||||||
properties={"Status": ["EXISTING", "DEMOLISH"]},
|
properties={"Status": ["EXISTING", "DEMOLISH"]},
|
||||||
pset_template=pset_template,
|
pset_template=pset_template,
|
||||||
)
|
)
|
||||||
facet = Property(propertySet="Pset_WallCommon", name="Status", value="EXISTING", datatype="IFCLABEL")
|
facet = Property(propertySet="Pset_WallCommon", baseName="Status", value="EXISTING", dataType="IFCLABEL")
|
||||||
run("Any matching value in an enumerated property will pass 1/3", facet=facet, inst=element, expected=True)
|
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", datatype="IFCLABEL")
|
facet = Property(propertySet="Pset_WallCommon", baseName="Status", value="DEMOLISH", dataType="IFCLABEL")
|
||||||
run("Any matching value in an enumerated property will pass 2/3", facet=facet, inst=element, expected=True)
|
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", datatype="IFCLABEL")
|
facet = Property(propertySet="Pset_WallCommon", baseName="Status", value="NEW", dataType="IFCLABEL")
|
||||||
run("Any matching value in an enumerated property will pass 3/3", facet=facet, inst=element, expected=False)
|
run("Any matching value in an enumerated property will pass 3/3", facet=facet, inst=element, expected=False)
|
||||||
|
|
||||||
ifc = self.setup_ifc()
|
ifc = self.setup_ifc()
|
||||||
@@ -1033,11 +1026,11 @@ class TestProperty:
|
|||||||
Name="Foo", ListValues=[ifc.createIfcLabel("X"), ifc.createIfcLabel("Y")]
|
Name="Foo", ListValues=[ifc.createIfcLabel("X"), ifc.createIfcLabel("Y")]
|
||||||
)
|
)
|
||||||
pset.HasProperties = [list_property]
|
pset.HasProperties = [list_property]
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="X", datatype="IFCLABEL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="X", dataType="IFCLABEL")
|
||||||
run("Any matching value in a list property will pass 1/3", facet=facet, inst=element, expected=True)
|
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", datatype="IFCLABEL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="Y", dataType="IFCLABEL")
|
||||||
run("Any matching value in a list property will pass 2/3", facet=facet, inst=element, expected=True)
|
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", datatype="IFCLABEL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="Z", dataType="IFCLABEL")
|
||||||
run("Any matching value in a list property will pass 3/3", facet=facet, inst=element, expected=False)
|
run("Any matching value in a list property will pass 3/3", facet=facet, inst=element, expected=False)
|
||||||
|
|
||||||
ifc = self.setup_ifc()
|
ifc = self.setup_ifc()
|
||||||
@@ -1050,13 +1043,13 @@ class TestProperty:
|
|||||||
SetPointValue=ifc.createIfcLengthMeasure(3000),
|
SetPointValue=ifc.createIfcLengthMeasure(3000),
|
||||||
)
|
)
|
||||||
pset.HasProperties = [bounded_property]
|
pset.HasProperties = [bounded_property]
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="1", datatype="IFCLENGTHMEASURE")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="1", dataType="IFCLENGTHMEASURE")
|
||||||
run("Any matching value in a bounded property will pass 1/4", facet=facet, inst=element, expected=True)
|
run("Any matching value in a bounded property will pass 1/4", facet=facet, inst=element, expected=True)
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="5", datatype="IFCLENGTHMEASURE")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="5", dataType="IFCLENGTHMEASURE")
|
||||||
run("Any matching value in a bounded property will pass 2/4", facet=facet, inst=element, expected=True)
|
run("Any matching value in a bounded property will pass 2/4", facet=facet, inst=element, expected=True)
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="3", datatype="IFCLENGTHMEASURE")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="3", dataType="IFCLENGTHMEASURE")
|
||||||
run("Any matching value in a bounded property will pass 3/4", facet=facet, inst=element, expected=True)
|
run("Any matching value in a bounded property will pass 3/4", facet=facet, inst=element, expected=True)
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="2", datatype="IFCLENGTHMEASURE")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="2", dataType="IFCLENGTHMEASURE")
|
||||||
run("Any matching value in a bounded property will pass 4/4", facet=facet, inst=element, expected=False)
|
run("Any matching value in a bounded property will pass 4/4", facet=facet, inst=element, expected=False)
|
||||||
|
|
||||||
ifc = self.setup_ifc()
|
ifc = self.setup_ifc()
|
||||||
@@ -1066,18 +1059,18 @@ class TestProperty:
|
|||||||
Name="Foo", DefiningValues=[ifc.createIfcLabel("X")], DefinedValues=[ifc.createIfcLengthMeasure(1000)]
|
Name="Foo", DefiningValues=[ifc.createIfcLabel("X")], DefinedValues=[ifc.createIfcLengthMeasure(1000)]
|
||||||
)
|
)
|
||||||
pset.HasProperties = [table_property]
|
pset.HasProperties = [table_property]
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="X", datatype="IFCLABEL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="X", dataType="IFCLABEL")
|
||||||
run("Any matching value in a table property will pass 1/3", facet=facet, inst=element, expected=True)
|
run("Any matching value in a table property will pass 1/3", facet=facet, inst=element, expected=True)
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="1", datatype="IFCLENGTHMEASURE")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="1", dataType="IFCLENGTHMEASURE")
|
||||||
run("Any matching value in a table property will pass 2/3", facet=facet, inst=element, expected=True)
|
run("Any matching value in a table property will pass 2/3", facet=facet, inst=element, expected=True)
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="Y", datatype="IFCLABEL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="Y", dataType="IFCLABEL")
|
||||||
run("Any matching value in a table property will pass 3/3", facet=facet, inst=element, expected=False)
|
run("Any matching value in a table property will pass 3/3", facet=facet, inst=element, expected=False)
|
||||||
|
|
||||||
ifc = self.setup_ifc()
|
ifc = self.setup_ifc()
|
||||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
||||||
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar")
|
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar")
|
||||||
pset.HasProperties = [ifc.createIfcPropertyReferenceValue(Name="Foo")]
|
pset.HasProperties = [ifc.createIfcPropertyReferenceValue(Name="Foo")]
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", datatype="IFCLABEL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", dataType="IFCLABEL")
|
||||||
run("Reference properties are treated as objects and not supported", facet=facet, inst=element, expected=False)
|
run("Reference properties are treated as objects and not supported", facet=facet, inst=element, expected=False)
|
||||||
|
|
||||||
ifc = self.setup_ifc()
|
ifc = self.setup_ifc()
|
||||||
@@ -1096,21 +1089,21 @@ class TestProperty:
|
|||||||
RelatingPropertyDefinition=pset,
|
RelatingPropertyDefinition=pset,
|
||||||
)
|
)
|
||||||
facet = Property(
|
facet = Property(
|
||||||
propertySet="Foo_Bar", name="PanelOperation", value="SWINGING", datatype="IFCDOORPANELOPERATIONENUM"
|
propertySet="Foo_Bar", baseName="PanelOperation", value="SWINGING", dataType="IFCDOORPANELOPERATIONENUM"
|
||||||
)
|
)
|
||||||
run("Predefined properties are supported but discouraged 1/2", facet=facet, inst=element, expected=True)
|
run("Predefined properties are supported but discouraged 1/2", facet=facet, inst=element, expected=True)
|
||||||
facet = Property(
|
facet = Property(
|
||||||
propertySet="Foo_Bar", name="PanelOperation", value="SWONGING", datatype="IFCDOORPANELOPERATIONENUM"
|
propertySet="Foo_Bar", baseName="PanelOperation", value="SWONGING", dataType="IFCDOORPANELOPERATIONENUM"
|
||||||
)
|
)
|
||||||
run("Predefined properties are supported but discouraged 2/2", facet=facet, inst=element, expected=False)
|
run("Predefined properties are supported but discouraged 2/2", facet=facet, inst=element, expected=False)
|
||||||
|
|
||||||
ifc = self.setup_ifc()
|
ifc = self.setup_ifc()
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", datatype="IFCLENGTHMEASURE")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", dataType="IFCLENGTHMEASURE")
|
||||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
||||||
qto = ifcopenshell.api.run("pset.add_qto", ifc, product=element, name="Foo_Bar")
|
qto = ifcopenshell.api.run("pset.add_qto", ifc, product=element, name="Foo_Bar")
|
||||||
ifcopenshell.api.run("pset.edit_qto", ifc, qto=qto, properties={"Foo": ifc.createIfcLengthMeasure(42)})
|
ifcopenshell.api.run("pset.edit_qto", ifc, qto=qto, properties={"Foo": ifc.createIfcLengthMeasure(42)})
|
||||||
run("A name check will match any quantity with any value", facet=facet, inst=element, expected=True)
|
run("A name check will match any quantity with any value", facet=facet, inst=element, expected=True)
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", datatype="IFCAREAMEASURE")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", dataType="IFCAREAMEASURE")
|
||||||
run("Quantities must also match the appropriate measure", facet=facet, inst=element, expected=False)
|
run("Quantities must also match the appropriate measure", facet=facet, inst=element, expected=False)
|
||||||
|
|
||||||
ifc = self.setup_ifc()
|
ifc = self.setup_ifc()
|
||||||
@@ -1119,9 +1112,9 @@ class TestProperty:
|
|||||||
complex_property = ifc.createIfcComplexProperty(Name="Foo", UsageName="RabbitAgilityTraining")
|
complex_property = ifc.createIfcComplexProperty(Name="Foo", UsageName="RabbitAgilityTraining")
|
||||||
ifcopenshell.api.run("pset.edit_pset", ifc, pset=complex_property, properties={"Rabbits": "Awesome"})
|
ifcopenshell.api.run("pset.edit_pset", ifc, pset=complex_property, properties={"Rabbits": "Awesome"})
|
||||||
pset.HasProperties = [complex_property]
|
pset.HasProperties = [complex_property]
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", datatype="IFCLABEL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", dataType="IFCLABEL")
|
||||||
run("Complex properties are not supported 1/2", facet=facet, inst=element, expected=False)
|
run("Complex properties are not supported 1/2", facet=facet, inst=element, expected=False)
|
||||||
facet = Property(propertySet="Foo", name="Rabbits", datatype="IFCLABEL")
|
facet = Property(propertySet="Foo", baseName="Rabbits", dataType="IFCLABEL")
|
||||||
run("Complex properties are not supported 2/2", facet=facet, inst=element, expected=False)
|
run("Complex properties are not supported 2/2", facet=facet, inst=element, expected=False)
|
||||||
|
|
||||||
ifc = self.setup_ifc()
|
ifc = self.setup_ifc()
|
||||||
@@ -1132,14 +1125,14 @@ class TestProperty:
|
|||||||
"pset.edit_qto", ifc, qto=complex_quantity, properties={"MyLength": ifc.createIfcLengthMeasure(42)}
|
"pset.edit_qto", ifc, qto=complex_quantity, properties={"MyLength": ifc.createIfcLengthMeasure(42)}
|
||||||
)
|
)
|
||||||
qto.Quantities = [complex_quantity]
|
qto.Quantities = [complex_quantity]
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", datatype="IFCLENGTHMEASURE")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", dataType="IFCLENGTHMEASURE")
|
||||||
run("Complex properties are not supported 1/2", facet=facet, inst=element, expected=False)
|
run("Complex properties are not supported 1/2", facet=facet, inst=element, expected=False)
|
||||||
facet = Property(propertySet="Foo", name="MyLength", datatype="IFCLENGTHMEASURE")
|
facet = Property(propertySet="Foo", baseName="MyLength", dataType="IFCLENGTHMEASURE")
|
||||||
run("Complex properties are not supported 2/2", facet=facet, inst=element, expected=False)
|
run("Complex properties are not supported 2/2", facet=facet, inst=element, expected=False)
|
||||||
|
|
||||||
ifc = self.setup_ifc()
|
ifc = self.setup_ifc()
|
||||||
restriction = Restriction(options={"pattern": "Foo_.*"})
|
restriction = Restriction(options={"pattern": "Foo_.*"})
|
||||||
facet = Property(propertySet=restriction, name="Foo", datatype="IFCLABEL")
|
facet = Property(propertySet=restriction, baseName="Foo", dataType="IFCLABEL")
|
||||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
||||||
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar")
|
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"})
|
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Bar"})
|
||||||
@@ -1152,7 +1145,7 @@ class TestProperty:
|
|||||||
|
|
||||||
ifc = self.setup_ifc()
|
ifc = self.setup_ifc()
|
||||||
restriction = Restriction(options={"pattern": "Foo.*"})
|
restriction = Restriction(options={"pattern": "Foo.*"})
|
||||||
facet = Property(propertySet="Foo_Bar", name=restriction, value="x", datatype="IFCLABEL")
|
facet = Property(propertySet="Foo_Bar", baseName=restriction, value="x", dataType="IFCLABEL")
|
||||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
||||||
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar")
|
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"})
|
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foobar": "x"})
|
||||||
@@ -1165,7 +1158,7 @@ class TestProperty:
|
|||||||
ifc = self.setup_ifc()
|
ifc = self.setup_ifc()
|
||||||
restriction1 = Restriction(options={"pattern": "Foo.*"})
|
restriction1 = Restriction(options={"pattern": "Foo.*"})
|
||||||
restriction2 = Restriction(options={"enumeration": ["x", "y"]})
|
restriction2 = Restriction(options={"enumeration": ["x", "y"]})
|
||||||
facet = Property(propertySet="Foo_Bar", name=restriction1, value=restriction2, datatype="IFCLABEL")
|
facet = Property(propertySet="Foo_Bar", baseName=restriction1, value=restriction2, dataType="IFCLABEL")
|
||||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
||||||
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar")
|
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"})
|
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foobar": "x", "Foobaz": "y"})
|
||||||
@@ -1184,7 +1177,7 @@ class TestProperty:
|
|||||||
)
|
)
|
||||||
|
|
||||||
ifc = self.setup_ifc()
|
ifc = self.setup_ifc()
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="2", datatype="IFCTIMEMEASURE")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="2", dataType="IFCTIMEMEASURE")
|
||||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
||||||
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar")
|
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)})
|
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcMassMeasure(2)})
|
||||||
@@ -1193,7 +1186,7 @@ class TestProperty:
|
|||||||
run("Measures are 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)
|
||||||
|
|
||||||
ifc = self.setup_ifc()
|
ifc = self.setup_ifc()
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="2", datatype="IFCLENGTHMEASURE")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="2", dataType="IFCLENGTHMEASURE")
|
||||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcWall")
|
||||||
pset = ifcopenshell.api.run("pset.add_pset", ifc, product=element, name="Foo_Bar")
|
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.createIfcLengthMeasure(2)})
|
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": ifc.createIfcLengthMeasure(2)})
|
||||||
@@ -1217,7 +1210,7 @@ class TestProperty:
|
|||||||
ifcopenshell.api.run("type.assign_type", ifc, related_object=wall, relating_type=wall_type)
|
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")
|
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"})
|
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Bar"})
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", datatype="IFCLABEL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", dataType="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 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)
|
run("Properties can be inherited from the type 2/2", facet=facet, inst=wall_type, expected=True)
|
||||||
|
|
||||||
@@ -1229,7 +1222,7 @@ class TestProperty:
|
|||||||
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Baz"})
|
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")
|
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"})
|
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset, properties={"Foo": "Bar"})
|
||||||
facet = Property(propertySet="Foo_Bar", name="Foo", value="Bar", datatype="IFCLABEL")
|
facet = Property(propertySet="Foo_Bar", baseName="Foo", value="Bar", dataType="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 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)
|
run("Properties can be overriden by an occurrence 2/2", facet=facet, inst=wall_type, expected=False)
|
||||||
|
|
||||||
@@ -1248,15 +1241,14 @@ class TestProperty:
|
|||||||
class TestMaterial:
|
class TestMaterial:
|
||||||
def test_creating_a_material_facet(self):
|
def test_creating_a_material_facet(self):
|
||||||
facet = Material()
|
facet = Material()
|
||||||
assert facet.asdict() == {"@maxOccurs": "unbounded"}
|
assert facet.asdict("requirement") == {"@cardinality": "required"}
|
||||||
facet = Material(
|
facet = Material(
|
||||||
value="value", uri="https://test.com", minOccurs="0", maxOccurs="unbounded", instructions="instructions"
|
value="value", uri="https://test.com", cardinality="required", instructions="instructions"
|
||||||
)
|
)
|
||||||
assert facet.asdict() == {
|
assert facet.asdict("requirement") == {
|
||||||
"value": {"simpleValue": "value"},
|
"value": {"simpleValue": "value"},
|
||||||
"@uri": "https://test.com",
|
"@uri": "https://test.com",
|
||||||
"@minOccurs": "0",
|
"@cardinality": "required",
|
||||||
"@maxOccurs": "unbounded",
|
|
||||||
"@instructions": "instructions",
|
"@instructions": "instructions",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1272,11 +1264,11 @@ class TestMaterial:
|
|||||||
run("Elements with any material will pass an empty material facet", facet=facet, inst=element, expected=True)
|
run("Elements with any material will pass an empty material facet", facet=facet, inst=element, expected=True)
|
||||||
|
|
||||||
run("A required facet checks all parameters as normal", facet=facet, inst=element, expected=True)
|
run("A required facet checks all parameters as normal", facet=facet, inst=element, expected=True)
|
||||||
facet = Material(minOccurs=0, maxOccurs=0)
|
facet = Material(cardinality="prohibited")
|
||||||
run("A prohibited facet returns the opposite of a required facet", facet=facet, inst=element, expected=False)
|
run("A prohibited facet returns the opposite of a required facet", facet=facet, inst=element, expected=False)
|
||||||
facet = Material(minOccurs=0)
|
facet = Material(cardinality="optional")
|
||||||
run("An optional facet always passes regardless of outcome 1/2", facet=facet, inst=element, expected=True)
|
run("An optional facet always passes regardless of outcome 1/2", facet=facet, inst=element, expected=True)
|
||||||
facet = Material(value="Foo", minOccurs=0)
|
facet = Material(value="Foo", cardinality="optional")
|
||||||
run("An optional facet always passes regardless of outcome 1/2", facet=facet, inst=element, expected=True)
|
run("An optional facet always passes regardless of outcome 1/2", facet=facet, inst=element, expected=True)
|
||||||
|
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
@@ -1406,23 +1398,21 @@ class TestMaterial:
|
|||||||
class TestPartOf:
|
class TestPartOf:
|
||||||
def test_creating_a_partof_facet(self):
|
def test_creating_a_partof_facet(self):
|
||||||
facet = PartOf()
|
facet = PartOf()
|
||||||
assert facet.asdict() == {"entity": {"name": {"simpleValue": "IFCWALL"}}, "@maxOccurs": "unbounded" }
|
assert facet.asdict("requirement") == {"entity": {"name": {"simpleValue": "IFCWALL"}}, "@cardinality": "required" }
|
||||||
facet = PartOf(
|
facet = PartOf(
|
||||||
name="IFCGROUP",
|
name="IFCGROUP",
|
||||||
predefinedType="predefinedType",
|
predefinedType="predefinedType",
|
||||||
relation="IFCRELASSIGNSTOGROUP",
|
relation="IFCRELASSIGNSTOGROUP",
|
||||||
minOccurs="0",
|
cardinality="required",
|
||||||
maxOccurs="unbounded",
|
|
||||||
instructions="instructions",
|
instructions="instructions",
|
||||||
)
|
)
|
||||||
assert facet.asdict() == {
|
assert facet.asdict("requirement") == {
|
||||||
"entity": {
|
"entity": {
|
||||||
"name": {"simpleValue": "IFCGROUP"},
|
"name": {"simpleValue": "IFCGROUP"},
|
||||||
"predefinedType": {"simpleValue": "predefinedType"},
|
"predefinedType": {"simpleValue": "predefinedType"},
|
||||||
},
|
},
|
||||||
"@relation": "IFCRELASSIGNSTOGROUP",
|
"@relation": "IFCRELASSIGNSTOGROUP",
|
||||||
"@minOccurs": "0",
|
"@cardinality": "required",
|
||||||
"@maxOccurs": "unbounded",
|
|
||||||
"@instructions": "instructions",
|
"@instructions": "instructions",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1440,11 +1430,8 @@ class TestPartOf:
|
|||||||
run("The aggregated part passes an aggregate relationship", facet=facet, inst=subelement, expected=True)
|
run("The aggregated part passes an aggregate relationship", facet=facet, inst=subelement, expected=True)
|
||||||
|
|
||||||
run("A required facet checks all parameters as normal", facet=facet, inst=subelement, expected=True)
|
run("A required facet checks all parameters as normal", facet=facet, inst=subelement, expected=True)
|
||||||
facet = PartOf(name="IFCELEMENTASSEMBLY", relation="IFCRELAGGREGATES", minOccurs=0, maxOccurs=0)
|
facet = PartOf(name="IFCELEMENTASSEMBLY", relation="IFCRELAGGREGATES", cardinality="prohibited")
|
||||||
run("A prohibited facet returns the opposite of a required facet", facet=facet, inst=subelement, expected=False)
|
run("A prohibited facet returns the opposite of a required facet", facet=facet, inst=subelement, expected=False)
|
||||||
facet = PartOf(name="IFCELEMENTASSEMBLY", relation="IFCRELAGGREGATES", minOccurs=0)
|
|
||||||
run("An optional facet always passes regardless of outcome 1/2", facet=facet, inst=element, expected=True)
|
|
||||||
run("An optional facet always passes regardless of outcome 2/2", facet=facet, inst=subelement, expected=True)
|
|
||||||
|
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcSlab")
|
element = ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcSlab")
|
||||||
|
|||||||
@@ -48,12 +48,11 @@ class TestIds:
|
|||||||
|
|
||||||
def test_create_an_ids_with_minimal_information(self):
|
def test_create_an_ids_with_minimal_information(self):
|
||||||
specs = ids.Ids()
|
specs = ids.Ids()
|
||||||
print('AAA', specs.asdict())
|
|
||||||
assert specs.asdict() == {
|
assert specs.asdict() == {
|
||||||
"@xmlns": "http://standards.buildingsmart.org/IDS",
|
"@xmlns": "http://standards.buildingsmart.org/IDS",
|
||||||
"@xmlns:xs": "http://www.w3.org/2001/XMLSchema",
|
"@xmlns:xs": "http://www.w3.org/2001/XMLSchema",
|
||||||
"@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
|
"@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
|
||||||
"@xsi:schemaLocation": "http://standards.buildingsmart.org/IDS http://standards.buildingsmart.org/IDS/0.9.6/ids.xsd",
|
"@xsi:schemaLocation": "http://standards.buildingsmart.org/IDS http://standards.buildingsmart.org/IDS/0.9.7/ids.xsd",
|
||||||
"info": {"title": "Untitled"},
|
"info": {"title": "Untitled"},
|
||||||
"specifications": {"specification": []},
|
"specifications": {"specification": []},
|
||||||
}
|
}
|
||||||
@@ -73,7 +72,7 @@ class TestIds:
|
|||||||
"@xmlns": "http://standards.buildingsmart.org/IDS",
|
"@xmlns": "http://standards.buildingsmart.org/IDS",
|
||||||
"@xmlns:xs": "http://www.w3.org/2001/XMLSchema",
|
"@xmlns:xs": "http://www.w3.org/2001/XMLSchema",
|
||||||
"@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
|
"@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
|
||||||
"@xsi:schemaLocation": "http://standards.buildingsmart.org/IDS http://standards.buildingsmart.org/IDS/0.9.6/ids.xsd",
|
"@xsi:schemaLocation": "http://standards.buildingsmart.org/IDS http://standards.buildingsmart.org/IDS/0.9.7/ids.xsd",
|
||||||
"info": {
|
"info": {
|
||||||
"title": "title",
|
"title": "title",
|
||||||
"copyright": "copyright",
|
"copyright": "copyright",
|
||||||
@@ -93,7 +92,7 @@ class TestIds:
|
|||||||
"@xmlns": "http://standards.buildingsmart.org/IDS",
|
"@xmlns": "http://standards.buildingsmart.org/IDS",
|
||||||
"@xmlns:xs": "http://www.w3.org/2001/XMLSchema",
|
"@xmlns:xs": "http://www.w3.org/2001/XMLSchema",
|
||||||
"@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
|
"@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
|
||||||
"@xsi:schemaLocation": "http://standards.buildingsmart.org/IDS http://standards.buildingsmart.org/IDS/0.9.6/ids.xsd",
|
"@xsi:schemaLocation": "http://standards.buildingsmart.org/IDS http://standards.buildingsmart.org/IDS/0.9.7/ids.xsd",
|
||||||
"info": {"title": "Untitled"},
|
"info": {"title": "Untitled"},
|
||||||
"specifications": {"specification": []},
|
"specifications": {"specification": []},
|
||||||
}
|
}
|
||||||
@@ -117,7 +116,7 @@ class TestIds:
|
|||||||
specs = ids.Ids(title="Title")
|
specs = ids.Ids(title="Title")
|
||||||
spec = ids.Specification(name="Name")
|
spec = ids.Specification(name="Name")
|
||||||
spec.applicability.append(ids.Entity(name="IFCWALL"))
|
spec.applicability.append(ids.Entity(name="IFCWALL"))
|
||||||
spec.requirements.append(name_attr := ids.Attribute(name="Name", value="Waldo"))
|
spec.requirements.append(ids.Attribute(name="Name", value="Waldo"))
|
||||||
specs.specifications.append(spec)
|
specs.specifications.append(spec)
|
||||||
assert "http://standards.buildingsmart.org/IDS" in specs.to_string()
|
assert "http://standards.buildingsmart.org/IDS" in specs.to_string()
|
||||||
assert spec.status == None
|
assert spec.status == None
|
||||||
@@ -233,12 +232,9 @@ class TestIds:
|
|||||||
class TestSpecification:
|
class TestSpecification:
|
||||||
def test_create_specification_with_minimal_information(self):
|
def test_create_specification_with_minimal_information(self):
|
||||||
spec = ids.Specification()
|
spec = ids.Specification()
|
||||||
print(spec.asdict())
|
|
||||||
assert spec.asdict() == {
|
assert spec.asdict() == {
|
||||||
"@name": "Unnamed",
|
"@name": "Unnamed",
|
||||||
"@ifcVersion": ["IFC2X3", "IFC4"],
|
"@ifcVersion": ["IFC2X3", "IFC4"],
|
||||||
"@minOccurs": 0,
|
|
||||||
"@maxOccurs": "unbounded",
|
|
||||||
"applicability": {},
|
"applicability": {},
|
||||||
"requirements": {},
|
"requirements": {},
|
||||||
}
|
}
|
||||||
@@ -255,8 +251,6 @@ class TestSpecification:
|
|||||||
)
|
)
|
||||||
assert spec.asdict() == {
|
assert spec.asdict() == {
|
||||||
"@name": "name",
|
"@name": "name",
|
||||||
"@minOccurs": 1,
|
|
||||||
"@maxOccurs": 1,
|
|
||||||
"@ifcVersion": "IFC4",
|
"@ifcVersion": "IFC4",
|
||||||
"@identifier": "identifier",
|
"@identifier": "identifier",
|
||||||
"@description": "description",
|
"@description": "description",
|
||||||
|
|||||||
Reference in New Issue
Block a user