From 4c47eb573aa66e617696fcc5bf311be8a0d45722 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 22 Jan 2026 11:18:35 +1100 Subject: [PATCH] Improve IDS static HTML reporter to report list of prohibited entities (they aren't passes or fails, just prohibited applicability) --- src/ifctester/ifctester/reporter.py | 24 +++++++++++ src/ifctester/ifctester/templates/report.html | 40 ++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/ifctester/ifctester/reporter.py b/src/ifctester/ifctester/reporter.py index 84684a10a2..e99e13ea8f 100644 --- a/src/ifctester/ifctester/reporter.py +++ b/src/ifctester/ifctester/reporter.py @@ -85,6 +85,7 @@ class ResultsSpecification(TypedDict): total_applicable: int total_applicable_pass: int total_applicable_fail: int + applicable_entities: list[ResultsEntity] percent_applicable_pass: ResultsPercent total_checks: int total_checks_pass: int @@ -383,6 +384,7 @@ class Json(Reporter): total_applicable=total_applicable, total_applicable_pass=total_applicable_pass, total_applicable_fail=total_applicable - total_applicable_pass, + applicable_entities=self.report_applicable_entities(specification), percent_applicable_pass=percent_applicable_pass, total_checks=total_checks, total_checks_pass=total_checks_pass, @@ -393,6 +395,24 @@ class Json(Reporter): requirements=requirements, ) + def report_applicable_entities(self, specification: Specification) -> list[ResultsEntity]: + return [ + ResultsEntity( + { + "element": e, + "element_type": 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), + } + ) + for e in specification.applicable_entities + ] + def report_passed_entities(self, requirement: Facet) -> list[ResultsEntity]: return [ ResultsEntity( @@ -459,6 +479,10 @@ class Html(Json): spec["is_prohibited"] = spec["cardinality"] == "prohibited" spec["cardinality"] = spec["cardinality"].capitalize() spec["has_requirements"] = bool(spec["requirements"]) + total_applicable_entities = len(spec["applicable_entities"]) + spec["applicable_entities"] = self.limit_entities(spec["applicable_entities"]) + spec["has_omitted_applicable"] = total_applicable_entities > self.entity_limit + spec["total_omitted_applicable"] = total_applicable_entities - self.entity_limit for requirement in spec["requirements"]: total_passed_entities = len(requirement["passed_entities"]) total_failed_entities = len(requirement["failed_entities"]) diff --git a/src/ifctester/ifctester/templates/report.html b/src/ifctester/ifctester/templates/report.html index 456e90e5f4..51beb5c0f5 100644 --- a/src/ifctester/ifctester/templates/report.html +++ b/src/ifctester/ifctester/templates/report.html @@ -152,7 +152,6 @@

Requirements

- {{/has_requirements}}
    {{#requirements}}
  1. @@ -252,6 +251,45 @@
  2. {{/requirements}}
+ {{/has_requirements}} + {{#is_prohibited}} + {{#total_applicable}} + + + + + + + + + + + + + {{#applicable_entities}} + + + + + + + + + {{#extra_of_type}} + + + + {{/extra_of_type}} + {{/applicable_entities}} + {{#has_omitted_applicable}} + + + + {{/has_omitted_applicable}} + +
ClassPredefinedTypeNameDescriptionGlobalIdTag
{{class}}{{predefined_type}}{{name}}{{description}}{{global_id}}{{tag}}
... {{extra_of_type}} more of the same element type ({{type_name}} with Tag {{type_tag}} and GlobalId {{type_global_id}}) not shown ...
... {{total_omitted_applicable}} more failing elements not shown out of {{total_applicable}} total ...
+ {{/total_applicable}} + {{/is_prohibited}} {{/specifications}}