From 83d25489781209940075e5cda2a4e372969af2ff Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Thu, 12 Aug 2021 13:10:16 +0200 Subject: [PATCH] Validate instance attribute values by catching exceptions --- .../ifcopenshell/validate.py | 61 ++++++++++++++----- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/validate.py b/src/ifcopenshell-python/ifcopenshell/validate.py index 1506138954..55ba010cf0 100644 --- a/src/ifcopenshell-python/ifcopenshell/validate.py +++ b/src/ifcopenshell-python/ifcopenshell/validate.py @@ -34,7 +34,9 @@ class json_logger: self.instance = instance def log(self, level, message, *args, **kwargs): - self.statements.append(log_entry_type(level, message % args, kwargs.get("instance"))._asdict()) + self.statements.append( + log_entry_type(level, message % args, kwargs.get("instance"))._asdict() + ) def __getattr__(self, level): return functools.partial(self.log, level, instance=self.instance) @@ -81,7 +83,9 @@ def assert_valid(attr, val, schema): if isinstance(attr_type, simple_type): invalid = type(val) != simple_type_python_mapping[attr_type.declared_type()] elif isinstance(attr_type, (entity_type, type_declaration)): - invalid = not isinstance(val, ifcopenshell.entity_instance) or not val.is_a(attr_type.name()) + invalid = not isinstance(val, ifcopenshell.entity_instance) or not val.is_a( + attr_type.name() + ) elif isinstance(attr_type, select_type): val_to_use = val if isinstance(schema.declaration_by_name(val.is_a()), enumeration_type): @@ -90,13 +94,19 @@ def assert_valid(attr, val, schema): else: invalid = True if not invalid: - invalid = not any(try_valid(x, val_to_use, schema) for x in attr_type.select_list()) + invalid = not any( + try_valid(x, val_to_use, schema) for x in attr_type.select_list() + ) elif isinstance(attr_type, enumeration_type): invalid = val not in attr_type.enumeration_items() elif isinstance(attr_type, aggregation_type): b1, b2 = attr_type.bound1(), attr_type.bound2() ty = attr_type.type_of_element() - invalid = len(val) < b1 or (b2 != -1 and len(val) > b2) or not all(assert_valid(ty, v, schema) for v in val) + invalid = ( + len(val) < b1 + or (b2 != -1 and len(val) > b2) + or not all(assert_valid(ty, v, schema) for v in val) + ) else: raise NotImplementedError("Not impl %s %s" % (type(attr_type), attr_type)) @@ -135,6 +145,7 @@ def validate(f, logger): logger.set_instance(inst) entity = schema.declaration_by_name(inst.is_a()) + attrs = entity.all_attributes() if entity.is_abstract(): e = "Entity %s is abstract" % entity.name() @@ -143,20 +154,38 @@ def validate(f, logger): else: logger.error("In %s\n%s", inst, e) - for attr, val, is_derived in zip(entity.all_attributes(), inst, entity.derived()): + has_invalid_value = False + for i in range(len(attrs)): + try: + inst[i] + pass + except: + if hasattr(logger, "set_instance"): + logger.error("Invalid attribute value for %s.%s", entity, attrs[i]) + else: + logger.error( + "In %s\nInvalid attribute value for %s.%s", + inst, + entity, + attrs[i], + ) + has_invalid_value = True - if val is None and not (is_derived or attr.optional()): - logger.error("Attribute %s.%s not optional", entity, attr) + if not has_invalid_value: + for attr, val, is_derived in zip(attrs, inst, entity.derived()): - if val is not None: - attr_type = attr.type_of_attribute() - try: - assert_valid(attr, val, schema) - except ValidationError as e: - if hasattr(logger, "set_instance"): - logger.error(str(e)) - else: - logger.error("In %s\n%s", inst, e) + if val is None and not (is_derived or attr.optional()): + logger.error("Attribute %s.%s not optional", entity, attr) + + if val is not None: + attr_type = attr.type_of_attribute() + try: + assert_valid(attr, val, schema) + except ValidationError as e: + if hasattr(logger, "set_instance"): + logger.error(str(e)) + else: + logger.error("In %s\n%s", inst, e) for attr in entity.all_inverse_attributes(): val = getattr(inst, attr.name())