@@ -284,7 +284,16 @@ def validate(f, logger):
284284 It is recommended to supply the path to the file, so that internal C++ errors reported during the parse stage
285285 are also captured.
286286 """
287+
288+ # Originally there was no way in Python to distinguish on an entity instance attribute value whether the
289+ # value supplied in the model was NIL ($) or 'missing because derived in subtype' (*). For validation this
290+ # however this may be important, and hence a feature switch has been implemented to return *-values as
291+ # instances of a dedicated type `ifcopenshell.ifcopenshell_wrapper.attribute_value_derived`.
292+ attribute_value_derived_org = ifcopenshell .ifcopenshell_wrapper .get_feature ('use_attribute_value_derived' )
293+ ifcopenshell .ifcopenshell_wrapper .set_feature ('use_attribute_value_derived' , True )
294+
287295 filename = None
296+
288297 if not isinstance (f , ifcopenshell .file ):
289298
290299 # get_log() clears log existing output
@@ -335,7 +344,18 @@ def validate(f, logger):
335344 zip (attrs , values , entity .derived ())
336345 ):
337346
338- if val is None and not (is_derived or attr .optional ()):
347+ if is_derived and not isinstance (val , ifcopenshell .ifcopenshell_wrapper .attribute_value_derived ):
348+ if hasattr (logger , "set_instance" ):
349+ logger .error ("Attribute %s.%s is derived in subtype" , entity , attr )
350+ else :
351+ logger .error (
352+ "For instance:\n %s\n %s\n With attribute:\n %s\n Derived in subtype\n " ,
353+ inst ,
354+ annotate_inst_attr_pos (inst , i ),
355+ attr ,
356+ )
357+
358+ if val is None and not attr .optional () and not is_derived :
339359 if hasattr (logger , "set_instance" ):
340360 logger .error ("Attribute %s.%s not optional" , entity , attr )
341361 else :
@@ -346,7 +366,7 @@ def validate(f, logger):
346366 attr ,
347367 )
348368
349- if val is not None :
369+ if val is not None and not is_derived :
350370 attr_type = attr .type_of_attribute ()
351371 try :
352372 assert_valid (attr_type , val , schema , attr = attr )
@@ -379,6 +399,8 @@ def validate(f, logger):
379399 # are verified.
380400 log_internal_cpp_errors (filename , logger )
381401
402+ # Restore the original value for 'use_attribute_value_derived'
403+ ifcopenshell .ifcopenshell_wrapper .set_feature ('use_attribute_value_derived' , attribute_value_derived_org )
382404
383405if __name__ == "__main__" :
384406 import sys
0 commit comments