mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-16 21:42:19 +00:00
A bunch of not so pretty validate.py performance improvements
This commit is contained in:
@@ -135,13 +135,28 @@ def assert_valid_inverse(attr, val, schema):
|
|||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
select_members_cache = {}
|
||||||
|
def get_select_members(schema, ty):
|
||||||
|
cache_key = schema.name(), ty.name()
|
||||||
|
from_cache = select_members_cache.get(cache_key)
|
||||||
|
if from_cache:
|
||||||
|
return from_cache
|
||||||
|
|
||||||
|
def inner(ty):
|
||||||
|
if isinstance(ty, select_type):
|
||||||
|
for st in ty.select_list():
|
||||||
|
yield from inner(st)
|
||||||
|
elif isinstance(ty, entity_type):
|
||||||
|
yield ty.name()
|
||||||
|
for st in ty.subtypes():
|
||||||
|
yield from inner(st)
|
||||||
|
elif isinstance(ty, type_declaration):
|
||||||
|
yield ty.name()
|
||||||
|
|
||||||
|
v = select_members_cache[cache_key] = set(inner(ty))
|
||||||
|
return v
|
||||||
|
|
||||||
def assert_valid(attr, val, schema):
|
def assert_valid(attr_type, val, schema, no_throw=False, attr=None):
|
||||||
if isinstance(attr, attribute):
|
|
||||||
attr_type = attr.type_of_attribute()
|
|
||||||
else:
|
|
||||||
attr_type = attr
|
|
||||||
|
|
||||||
type_wrappers = (named_type,)
|
type_wrappers = (named_type,)
|
||||||
if not isinstance(val, ifcopenshell.entity_instance):
|
if not isinstance(val, ifcopenshell.entity_instance):
|
||||||
# If val is not an entity instance we need to
|
# If val is not an entity instance we need to
|
||||||
@@ -172,9 +187,13 @@ def assert_valid(attr, val, schema):
|
|||||||
else:
|
else:
|
||||||
invalid = True
|
invalid = True
|
||||||
if not invalid:
|
if not invalid:
|
||||||
invalid = not any(
|
# Previously we relied on `is_a(x) for x in attr_type.select_items()`
|
||||||
try_valid(x, val_to_use, schema) for x in attr_type.select_list()
|
# this was linear in the number of select leafs, which is very large
|
||||||
)
|
# for e.g IfcValue, which is an often used select. Therefore, we now
|
||||||
|
# calculate (and cache) the select leafs (including entity subtypes)
|
||||||
|
# for the select definition and simply check for membership in this
|
||||||
|
# set.
|
||||||
|
invalid = val_to_use.is_a() not in get_select_members(schema, attr_type)
|
||||||
elif isinstance(attr_type, enumeration_type):
|
elif isinstance(attr_type, enumeration_type):
|
||||||
invalid = val not in attr_type.enumeration_items()
|
invalid = val not in attr_type.enumeration_items()
|
||||||
elif isinstance(attr_type, aggregation_type):
|
elif isinstance(attr_type, aggregation_type):
|
||||||
@@ -188,19 +207,14 @@ def assert_valid(attr, val, schema):
|
|||||||
else:
|
else:
|
||||||
raise NotImplementedError("Not impl %s %s" % (type(attr_type), attr_type))
|
raise NotImplementedError("Not impl %s %s" % (type(attr_type), attr_type))
|
||||||
|
|
||||||
if invalid:
|
if no_throw:
|
||||||
|
return not invalid
|
||||||
|
elif invalid:
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
f"With attribute:\n {attr}\nValue:\n {val}\nNot valid\n"
|
f"With attribute:\n {attr or attr_type}\nValue:\n {val}\nNot valid\n"
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def try_valid(attr, val, schema):
|
|
||||||
try:
|
|
||||||
return assert_valid(attr, val, schema)
|
|
||||||
except ValidationError as e:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def log_internal_cpp_errors(filename, logger):
|
def log_internal_cpp_errors(filename, logger):
|
||||||
@@ -235,6 +249,21 @@ def log_internal_cpp_errors(filename, logger):
|
|||||||
else:
|
else:
|
||||||
logger.error("For instance:\n %s\n%s", line, m)
|
logger.error("For instance:\n %s\n%s", line, m)
|
||||||
|
|
||||||
|
entity_attribute_map = {}
|
||||||
|
def get_entity_attributes(schema, entity):
|
||||||
|
cache_key = schema.name(), entity
|
||||||
|
from_cache = entity_attribute_map.get(cache_key)
|
||||||
|
if from_cache:
|
||||||
|
return from_cache
|
||||||
|
|
||||||
|
entity_attrs = (
|
||||||
|
ent := schema.declaration_by_name(entity),
|
||||||
|
ent.all_attributes(),
|
||||||
|
)
|
||||||
|
|
||||||
|
entity_attribute_map[cache_key] = entity_attrs
|
||||||
|
return entity_attrs
|
||||||
|
|
||||||
|
|
||||||
def validate(f, logger):
|
def validate(f, logger):
|
||||||
"""
|
"""
|
||||||
@@ -273,9 +302,8 @@ def validate(f, logger):
|
|||||||
if hasattr(logger, "set_instance"):
|
if hasattr(logger, "set_instance"):
|
||||||
logger.set_instance(inst)
|
logger.set_instance(inst)
|
||||||
|
|
||||||
entity = schema.declaration_by_name(inst.is_a())
|
entity, attrs = get_entity_attributes(schema, inst.is_a())
|
||||||
attrs = entity.all_attributes()
|
|
||||||
|
|
||||||
if entity.is_abstract():
|
if entity.is_abstract():
|
||||||
e = "Entity %s is abstract" % entity.name()
|
e = "Entity %s is abstract" % entity.name()
|
||||||
if hasattr(logger, "set_instance"):
|
if hasattr(logger, "set_instance"):
|
||||||
@@ -284,9 +312,10 @@ def validate(f, logger):
|
|||||||
logger.error("For instance:\n %s\n%s", inst, e)
|
logger.error("For instance:\n %s\n%s", inst, e)
|
||||||
|
|
||||||
has_invalid_value = False
|
has_invalid_value = False
|
||||||
|
values = [None] * len(attrs)
|
||||||
for i in range(len(attrs)):
|
for i in range(len(attrs)):
|
||||||
try:
|
try:
|
||||||
inst[i]
|
values[i] = inst[i]
|
||||||
pass
|
pass
|
||||||
except:
|
except:
|
||||||
if hasattr(logger, "set_instance"):
|
if hasattr(logger, "set_instance"):
|
||||||
@@ -303,7 +332,7 @@ def validate(f, logger):
|
|||||||
|
|
||||||
if not has_invalid_value:
|
if not has_invalid_value:
|
||||||
for i, (attr, val, is_derived) in enumerate(
|
for i, (attr, val, is_derived) in enumerate(
|
||||||
zip(attrs, inst, entity.derived())
|
zip(attrs, values, entity.derived())
|
||||||
):
|
):
|
||||||
|
|
||||||
if val is None and not (is_derived or attr.optional()):
|
if val is None and not (is_derived or attr.optional()):
|
||||||
@@ -320,7 +349,7 @@ def validate(f, logger):
|
|||||||
if val is not None:
|
if val is not None:
|
||||||
attr_type = attr.type_of_attribute()
|
attr_type = attr.type_of_attribute()
|
||||||
try:
|
try:
|
||||||
assert_valid(attr, val, schema)
|
assert_valid(attr_type, val, schema, attr=attr)
|
||||||
except ValidationError as e:
|
except ValidationError as e:
|
||||||
if hasattr(logger, "set_instance"):
|
if hasattr(logger, "set_instance"):
|
||||||
logger.error(str(e))
|
logger.error(str(e))
|
||||||
|
|||||||
Reference in New Issue
Block a user