Capture SPF specific errors in validation test

This commit is contained in:
Thomas Krijnen
2025-09-10 09:40:20 +02:00
parent a50fc3184b
commit 231d047ce9
2 changed files with 44 additions and 13 deletions
@@ -311,17 +311,22 @@ def assert_valid(
return True
def log_internal_cpp_errors(f: ifcopenshell.file, filename: str, logger: Union[Logger, json_logger]) -> None:
def log_internal_cpp_errors(
f: Optional[ifcopenshell.file], filename: str, logger: Union[Logger, json_logger], log_content: Optional[str] = None
) -> None:
import re
import bisect
chr_offset_re = re.compile(r"at offset (\d+)\s*")
for_instance_re = re.compile(r"\s*for instance #(\d+)\s*")
log = ifcopenshell.get_log()
msgs = list(map(json.loads, filter(None, log.split("\n"))))
if log_content is None:
log_content = ifcopenshell.get_log()
msgs = list(map(json.loads, filter(None, log_content.split("\n"))))
chr_offsets = [chr_offset_re.findall(m["message"]) for m in msgs]
if chr_offsets:
instance_messages = [for_instance_re.findall(m["message"]) for m in msgs]
if chr_offsets or (instance_messages and f is None):
# The file is opened in binary mode, in order
# to correspond with the offsets reported by
# IfcOpenShell C++
@@ -342,15 +347,25 @@ def log_internal_cpp_errors(f: ifcopenshell.file, filename: str, logger: Union[L
else:
logger.error("For instance:\n %s\n%s", line, m)
instance_messages = [for_instance_re.findall(m["message"]) for m in msgs]
if instance_messages:
for instid, msg in zip(instance_messages, msgs):
if instid:
m = for_instance_re.sub("", msg["message"])
try:
inst = f[int(instid[0])]
except:
inst = None
if f is not None:
try:
inst = f[int(instid[0])]
except:
inst = None
else:
inst = next(
(
l
for l in lines
if l.strip().startswith(f"#{instid}".encode("ascii"))
and re.sub(r"\s+", "", l).startswith(f"#{instid}=".encode("ascii"))
),
None,
)
if isinstance(logger, json_logger):
logger.set_state("instance", inst)
logger.set_state("attribute", None)
@@ -629,7 +644,7 @@ def to_string_header_entity(header_entity):
def validate_ifc_header(
f: Union[ifcopenshell.file, ifcopenshell.simple_spf.file], logger: Union[Logger, json_logger]
) -> None:
# @todo now that we have the header schema compiled into ifcopenshell, and the
# @todo now that we have the header schema compiled into ifcopenshell, and the
# header instances being conventional entity instances, this specific logic should
# not be necessary anymore.
header: Union[ifcopenshell.entity_instance, types.SimpleNamespace] = f.header
@@ -637,7 +652,11 @@ def validate_ifc_header(
STRING_TYPE = "STRING (256)"
def log_error(
header_entity: Union[ifcopenshell.entity_instance, tuple], name: str, index: int, expected_type: str, provided_type: str
header_entity: Union[ifcopenshell.entity_instance, tuple],
name: str,
index: int,
expected_type: str,
provided_type: str,
) -> None:
logger.error(
(
@@ -652,7 +671,9 @@ def validate_ifc_header(
provided_type,
)
def validate_attribute(header_entity: ifcopenshell.entity_instance, name: str, index: int, *, aggregate: bool = False) -> None:
def validate_attribute(
header_entity: ifcopenshell.entity_instance, name: str, index: int, *, aggregate: bool = False
) -> None:
try:
value = getattr(header_entity, name)
except RuntimeError as _: