mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user