ifctester.reporter

Module Contents

class ifctester.reporter.Bcf(ids: ifctester.ids.Ids, hide_skipped=False)

Bases: Json

report_failed_entities(requirement: ifctester.facet.Facet) → list[ifctester.facet.FacetFailure]
to_file(filepath: str) → None
class ifctester.reporter.Console(ids: ifctester.ids.Ids, use_colour=True)

Bases: Reporter

print(txt: str, end: str | None = None)
report() → None
report_reason(failure: ifctester.facet.FacetFailure) → None
report_specification(specification: ifctester.ids.Specification) → None
set_style(*colours: str)
colours
use_colour = True
class ifctester.reporter.Html(ids: ifctester.ids.Ids, hide_skipped: bool = False)

Bases: Json

group_by_type(entities)
limit_entities(entities)
report() → None
to_file(filepath: str) → None
to_string() → str
entity_limit = 100
class ifctester.reporter.Json(ids: ifctester.ids.Ids, hide_skipped=False)

Bases: Reporter

encode(obj)
report() → Results
report_applicable_entities(specification: ifctester.ids.Specification) → list[ResultsEntity]
report_failed_entities(requirement: ifctester.facet.Facet) → list[ResultsEntity]
report_passed_entities(requirement: ifctester.facet.Facet) → list[ResultsEntity]
report_specification(specification: ifctester.ids.Specification) → ResultsSpecification
to_file(filepath: str) → None
to_string() → str
results
class ifctester.reporter.Ods(ids: ifctester.ids.Ids, excel_safe=False)

Bases: Json

excel_safe_spreadsheet_name(name: str) → str
to_file(filepath: str) → None
colours
excel_safe = False
class ifctester.reporter.OdsSummary(ids: ifctester.ids.Ids, excel_safe=False)

Bases: Json

excel_safe_spreadsheet_name(name: str) → str
to_file(filepath: str) → None
colours
excel_safe = False
class ifctester.reporter.Reporter(ids: ifctester.ids.Ids)
report(ids)
to_string()
write(filepath)
ids
class ifctester.reporter.Results

Bases: TypedDict

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object’s

(key, value) pairs

dict(iterable) -> new dictionary initialized as if via:

d = {} for k, v in iterable:

d[k] = v

dict(**kwargs) -> new dictionary initialized with the name=value pairs

in the keyword argument list. For example: dict(one=1, two=2)

Initialize self. See help(type(self)) for accurate signature.

date: str
filename: str
filepath: str
hide_skipped: bool
percent_checks_pass: ResultsPercent
percent_requirements_pass: ResultsPercent
percent_specifications_pass: ResultsPercent
specifications: list[ResultsSpecification]
status: bool
title: str
total_checks: int
total_checks_fail: int
total_checks_pass: int
total_requirements: int
total_requirements_fail: int
total_requirements_pass: int
total_specifications: int
total_specifications_fail: int
total_specifications_pass: int
class ifctester.reporter.ResultsRequirement

Bases: TypedDict

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object’s

(key, value) pairs

dict(iterable) -> new dictionary initialized as if via:

d = {} for k, v in iterable:

d[k] = v

dict(**kwargs) -> new dictionary initialized with the name=value pairs

in the keyword argument list. For example: dict(one=1, two=2)

Initialize self. See help(type(self)) for accurate signature.

description: str
facet_type: str
failed_entities: list[ResultsEntity]
has_omitted_failures: NotRequired[bool]
has_omitted_passes: NotRequired[bool]
instructions: NotRequired[str | None]
label: str
metadata: dict
passed_entities: list[ResultsEntity]
percent_pass: ResultsPercent
status: bool
total_applicable: int
total_fail: int
total_failed_entities: NotRequired[int]
total_omitted_failures: NotRequired[int]
total_omitted_passes: NotRequired[int]
total_pass: int
total_passed_entities: NotRequired[int]
value: str
class ifctester.reporter.ResultsSpecification

Bases: TypedDict

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object’s

(key, value) pairs

dict(iterable) -> new dictionary initialized as if via:

d = {} for k, v in iterable:

d[k] = v

dict(**kwargs) -> new dictionary initialized with the name=value pairs

in the keyword argument list. For example: dict(one=1, two=2)

Initialize self. See help(type(self)) for accurate signature.

applicability: list[str]
applicable_entities: list[ResultsEntity]
cardinality: str
description: str
has_omitted_applicable: NotRequired[bool]
has_requirements: NotRequired[bool]
instructions: str
is_ifc_version: bool
is_prohibited: NotRequired[bool]
is_skipped: bool
name: str
percent_applicable_pass: ResultsPercent
percent_checks_pass: ResultsPercent
requirements: list[ResultsRequirement]
status: bool
total_applicable: int
total_applicable_fail: int
total_applicable_pass: int
total_checks: int
total_checks_fail: int
total_checks_pass: int
total_omitted_applicable: NotRequired[int]
class ifctester.reporter.Sqlite(ids: ifctester.ids.Ids)

Bases: Reporter

Stores audit results in a normalised SQLite database.

Where Json repeats every entity’s attributes once per specification and once more per requirement, entities are stored once in the entity table and referenced by ID everywhere else. Only failures are stored: a passing check is any applicable entity without a failure row, which the passed view derives on demand.

This keeps reports for large models orders of magnitude smaller, and lets consumers page through results with a query instead of parsing an entire document. Note that report is a no-op: rows are written during to_file so that no intermediate result tree is ever built.

get_entity_row(element: ifcopenshell.entity_instance, type_id: int | None) → tuple
get_reason_id(reason: str) → int
iter_entity_rows(elements: collections.abc.Iterable[ifcopenshell.entity_instance]) → collections.abc.Iterator[tuple]

Yield rows for elements not yet written, and for the types they occur as.

report() → None

Results are written directly to the database in to_file, so that no intermediate result tree is materialised in memory.

to_file(filepath: str) → None
abstractmethod to_string() → str
write_meta(db: sqlite3.Connection) → None
write_requirement(db: sqlite3.Connection, specification: ifctester.ids.Specification, specification_id: int, requirement: ifctester.facet.Facet, requirement_id: int) → int

Write a requirement and its failures. Returns the number of passing checks.

write_specification(db: sqlite3.Connection, specification: ifctester.ids.Specification, specification_id: int, requirement_id: int) → int

Write a specification and its requirements. Returns the next free requirement ID.

INDEXES = Multiline-String
Show Value
"""
        CREATE INDEX idx_requirement_specification ON requirement(specification_id);
        CREATE INDEX idx_applicability_specification ON applicability(specification_id);
        CREATE INDEX idx_applicability_entity ON applicability(entity_id);
        CREATE INDEX idx_failure_requirement ON failure(requirement_id);
        CREATE INDEX idx_failure_entity ON failure(entity_id);
    """
SCHEMA = Multiline-String
Show Value
"""
        CREATE TABLE meta (
            key TEXT PRIMARY KEY,
            value TEXT  -- All values are stored as text
        );

        CREATE TABLE entity (
            id INTEGER PRIMARY KEY,  -- The IFC STEP ID
            global_id TEXT,
            class TEXT,
            predefined_type TEXT,
            name TEXT,
            description TEXT,
            tag TEXT,
            type_id INTEGER REFERENCES entity(id)
        );

        CREATE TABLE specification (
            id INTEGER PRIMARY KEY,
            name TEXT,
            description TEXT,
            instructions TEXT,
            cardinality TEXT,
            applicability TEXT,  -- One human readable clause per line
            status INTEGER,  -- 1 pass, 0 fail, NULL untested
            is_ifc_version INTEGER,
            is_skipped INTEGER,
            total_applicable INTEGER,
            total_applicable_pass INTEGER,
            total_checks INTEGER,
            total_checks_pass INTEGER
        );

        CREATE TABLE requirement (
            id INTEGER PRIMARY KEY,
            specification_id INTEGER REFERENCES specification(id),
            facet_type TEXT,
            label TEXT,
            value TEXT,
            description TEXT,
            instructions TEXT,
            metadata TEXT,  -- The facet as JSON
            status INTEGER,
            total_applicable INTEGER,
            total_pass INTEGER,
            total_fail INTEGER
        );

        -- Failure reasons are interned, as the same reason typically applies
        -- to thousands of entities.
        CREATE TABLE reason (
            id INTEGER PRIMARY KEY,
            text TEXT
        );

        CREATE TABLE applicability (
            specification_id INTEGER REFERENCES specification(id),
            entity_id INTEGER REFERENCES entity(id)
        );

        CREATE TABLE failure (
            requirement_id INTEGER REFERENCES requirement(id),
            entity_id INTEGER REFERENCES entity(id),
            reason_id INTEGER REFERENCES reason(id)
        );

        -- Passes are derived, not stored: an applicable entity with no failure.
        CREATE VIEW passed AS
        SELECT r.id AS requirement_id, a.entity_id AS entity_id
        FROM requirement r
        JOIN applicability a ON a.specification_id = r.specification_id
        LEFT JOIN failure f ON f.requirement_id = r.id AND f.entity_id = a.entity_id
        WHERE f.entity_id IS NULL;
    """
SCHEMA_VERSION = 1
entity_ids: set[int]
reasons: dict[str, int]
class ifctester.reporter.Txt(ids: ifctester.ids.Ids)

Bases: Console

print(txt: str, end: str | None = None)
to_file(filepath: str) → None
to_string() → None
text = ''
ifctester.reporter.get_cardinality(specification: ifctester.ids.Specification) → str
ifctester.reporter.get_requirement_label_value(requirement: ifctester.facet.Facet) → tuple[str | None, str]

Derive a human readable label and value for a requirement facet.

Facet attributes may hold a Restriction rather than a plain string, so both are coerced to text. Only PartOf.relation may legitimately be None.

ifctester.reporter.ResultsEntity
ifctester.reporter.ResultsPercent
ifctester.reporter.cwd