Fix #4427. Failures are now stored in single dictionary.

There was a missing clear() call to failed_reasons which could lead to incorrect reporting. It also makes no sense to store them separately.
This commit is contained in:
Dion Moult
2024-03-29 15:06:59 +11:00
parent ed8eb7543b
commit bd92c043e0
3 changed files with 27 additions and 29 deletions
+2 -3
View File
@@ -56,8 +56,7 @@ def get_psets(element):
class Facet:
def __init__(self, *parameters):
self.status = None
self.failed_entities: List[Facet] = []
self.failed_reasons: List[str] = []
self.failures = []
for i, name in enumerate(self.parameters):
setattr(self, name.replace("@", ""), parameters[i])
@@ -96,7 +95,7 @@ class Facet:
templates = self.applicability_templates
elif clause_type == "requirement":
is_prohibited = False
if specification.cardinality == "prohibited":
if specification.maxOccurs == 0:
is_prohibited = not is_prohibited
if requirement.cardinality == "prohibited":
is_prohibited = not is_prohibited
+5 -6
View File
@@ -193,7 +193,7 @@ class Specification:
self.description = ids_dict.get("@description", "")
self.instructions = ids_dict.get("@instructions", "")
self.minOccurs = ids_dict.get("applicability", {}).get("@minOccurs", 0)
self.maxOccurs = ids_dict.get("applicability", {}).get("@minOccurs", "unbounded")
self.maxOccurs = ids_dict.get("applicability", {}).get("@maxOccurs", "unbounded")
self.ifcVersion = ids_dict["@ifcVersion"]
self.applicability = (
self.parse_clause(ids_dict["applicability"]) if ids_dict.get("applicability", None) is not None else []
@@ -221,7 +221,7 @@ class Specification:
self.failed_entities: Set[Entity] = set()
for facet in self.requirements:
facet.status = None
facet.failed_entities.clear()
facet.failures.clear()
self.status = None
def validate(self, ifc_file, filter_version=False):
@@ -250,16 +250,15 @@ class Specification:
result = facet(element)
if not bool(result):
self.failed_entities.add(element)
facet.failed_entities.append(element)
facet.failed_reasons.append(str(result))
facet.failures.append({"element": element, "reason": str(result)})
for facet in self.requirements:
if facet.cardinality == "required":
facet.status = not bool(facet.failed_entities)
facet.status = not bool(facet.failures)
elif facet.cardinality == "optional":
facet.status = True
elif facet.cardinality == "prohibited":
facet.status = bool(facet.failed_entities)
facet.status = bool(facet.failures)
self.status = True
if self.minOccurs != 0:
+20 -20
View File
@@ -105,19 +105,19 @@ class Console(Reporter):
for requirement in specification.requirements:
self.set_style("reset")
self.set_style("red") if requirement.failed_entities else self.set_style("green")
self.set_style("red") if requirement.failures else self.set_style("green")
self.print(" " * 8 + requirement.to_string("requirement", specification, requirement))
self.set_style("reset")
for i, element in enumerate(requirement.failed_entities[0:10]):
for failure in requirement.failures[0:10]:
self.print(" " * 12, end="")
self.report_reason(requirement.failed_reasons[i], element)
if len(requirement.failed_entities) > 10:
self.print(" " * 12 + f"... {len(requirement.failed_entities)} in total ...")
self.report_reason(failure)
if len(requirement.failures) > 10:
self.print(" " * 12 + f"... {len(requirement.failures)} in total ...")
self.set_style("reset")
def report_reason(self, reason, element):
def report_reason(self, failure):
is_bold = False
for substring in reason.split('"'):
for substring in failure["reason"].split('"'):
if is_bold:
self.set_style("purple")
else:
@@ -125,7 +125,7 @@ class Console(Reporter):
self.print(substring, end="")
is_bold = not is_bold
self.set_style("grey")
self.print(" - " + str(element))
self.print(" - " + str(failure["element"]))
self.set_style("reset")
def set_style(self, *colours):
@@ -212,7 +212,7 @@ class Json(Reporter):
total_checks_pass = 0
requirements = []
for requirement in specification.requirements:
total_fail = len(requirement.failed_entities)
total_fail = len(requirement.failures)
total_pass = total_applicable - total_fail
percent_pass = math.floor((total_pass / total_applicable) * 100) if total_applicable else "N/A"
total_checks += total_applicable
@@ -254,18 +254,18 @@ class Json(Reporter):
def report_failed_entities(self, requirement):
return [
{
"reason": requirement.failed_reasons[i],
"element": str(e),
"element_type": str(ifcopenshell.util.element.get_type(e)),
"class": e.is_a(),
"predefined_type": ifcopenshell.util.element.get_predefined_type(e),
"name": getattr(e, "Name", None),
"description": getattr(e, "Description", None),
"id": e.id(),
"global_id": getattr(e, "GlobalId", None),
"tag": getattr(e, "Tag", None),
"reason": f["reason"],
"element": str(f["element"]),
"element_type": str(ifcopenshell.util.element.get_type(f["element"])),
"class": f["element"].is_a(),
"predefined_type": ifcopenshell.util.element.get_predefined_type(f["element"]),
"name": getattr(f["element"], "Name", None),
"description": getattr(f["element"], "Description", None),
"id": f["element"].id(),
"global_id": getattr(f["element"], "GlobalId", None),
"tag": getattr(f["element"], "Tag", None),
}
for i, e in enumerate(requirement.failed_entities)
for f in requirement.failures
]
def to_string(self):