3333 logging = type ("logger" , (object ,), {"exception" : staticmethod (lambda s : print (s ))})
3434
3535
36+ def set_derived_atribute (* args ):
37+ raise TypeError ("Unable to set derived attribute" )
38+
39+
40+ # For every schema and its entities populate a list
41+ # of functions for every entity attribute (including
42+ # inherited attributes) to set that particular
43+ # attribute by index.
44+ # For example. IFC2X3.IfcWall with have a list of
45+ # 9 methods. The first will point at
46+ # ifcopenshell.ifcopenshell_wrapper.entity_instance.setArgumentAsString
47+ # because the first attribute GlobalId ultimately
48+ # is of type string.
49+ # Previously, resolving the appropriate function was
50+ # done for each invocation of __setitem__. Now this
51+ # mapping is built once during initialization of the
52+ # module.
53+ _method_dict = {}
54+ for nm in ifcopenshell_wrapper .schema_names ():
55+ schema = ifcopenshell_wrapper .schema_by_name (nm )
56+ for decl in schema .declarations ():
57+ if isinstance (decl , ifcopenshell_wrapper .entity ):
58+ fq_name = "." .join ((nm , decl .name ()))
59+
60+ # get type strings as reported by IfcOpenShell C++
61+ type_strs = decl .argument_types ()
62+
63+ # convert case for setter function
64+ type_strs = [x .title ().replace (" " , "" ) for x in type_strs ]
65+
66+ # binary and enumeration are passed from python as string as well
67+ type_strs = [x .replace ("Binary" , "String" ) for x in type_strs ]
68+ type_strs = [x .replace ("Enumeration" , "String" ) for x in type_strs ]
69+
70+ # prefix to get method names
71+ fn_names = ["setArgumentAs" + x for x in type_strs ]
72+
73+ # resolve to actual functions in wrapper
74+ functions = [
75+ set_derived_atribute if mname == "setArgumentAsDerived" else getattr (ifcopenshell_wrapper .entity_instance , mname ) \
76+ for mname in fn_names ]
77+
78+ _method_dict [fq_name ] = functions
79+
80+
3681class entity_instance (object ):
3782 """This is the base Python class for all IFC objects.
3883
@@ -52,6 +97,7 @@ def __init__(self, e, file=None):
5297 if isinstance (e , tuple ):
5398 e = ifcopenshell_wrapper .new_IfcBaseClass (* e )
5499 super (entity_instance , self ).__setattr__ ("wrapped_data" , e )
100+ super (entity_instance , self ).__setattr__ ("method_list" , None )
55101 self .wrapped_data .file = file
56102
57103 def __getattr__ (self , name ):
@@ -65,7 +111,7 @@ def __getattr__(self, name):
65111 return entity_instance .wrap_value (self .wrapped_data .get_inverse (name ), self .wrapped_data .file )
66112 else :
67113 raise AttributeError (
68- "entity instance of type '%s' has no attribute '%s'" % (self .wrapped_data .is_a (), name )
114+ "entity instance of type '%s' has no attribute '%s'" % (self .wrapped_data .is_a (True ), name )
69115 )
70116
71117 @staticmethod
@@ -129,38 +175,16 @@ def __setitem__(self, idx, value):
129175 if self .wrapped_data .file and self .wrapped_data .file .transaction :
130176 self .wrapped_data .file .transaction .store_edit (self , idx , value )
131177
132- attr_type = real_attr_type = self .attribute_type ( idx ). title (). replace ( " " , "" )
133- real_attr_type = real_attr_type . replace ( "Derived " , "None" )
134- attr_type = attr_type . replace ( "Binary" , "String" )
135- attr_type = attr_type . replace ( "Enumeration" , "String" )
136-
178+ if self .method_list is None :
179+ super ( entity_instance , self ). __setattr__ ( "method_list " , _method_dict [ self . is_a ( True )] )
180+
181+ method = self . method_list [ idx ]
182+
137183 if value is None :
138- if attr_type != "Derived" :
184+ if method is not set_derived_atribute :
139185 self .wrapped_data .setArgumentAsNull (idx )
140- else :
141- valid = attr_type != "Derived"
142- if valid :
143- try :
144- if isinstance (value , unicode ):
145- value = value .encode ("utf-8" )
146- except BaseException :
147- pass
148-
149- try :
150- if attr_type != "Derived" :
151- getattr (self .wrapped_data , "setArgumentAs%s" % attr_type )(
152- idx , entity_instance .unwrap_value (value )
153- )
154- except BaseException as e :
155- import traceback
156- traceback .print_exc ()
157- valid = False
158-
159- if not valid :
160- raise ValueError (
161- "Expected %s for attribute %s.%s, got %r"
162- % (real_attr_type , self .is_a (), self .attribute_name (idx ), value )
163- )
186+ else :
187+ self .method_list [idx ](self .wrapped_data , idx , entity_instance .unwrap_value (value ))
164188
165189 return value
166190
0 commit comments