1 # -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2010-2019 CEA/DEN, EDF R&D, OPEN CASCADE
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License, or (at your option) any later version.
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 ## \defgroup datamodeler datamodeler
23 # \details Helper for modeling user data
27 __date__ ="$15 avr. 2010 19:44:17$"
29 #from .uiexception import DevelException
31 # Most usable class types
32 TypeString= "".__class__
34 TypeInteger = __ref_integer.__class__
36 TypeDouble = __ref_double.__class__
38 TypeList = __ref_list.__class__
40 TypeDictionnary = __ref_dict.__class__
41 from .enumerate import Enumerate
43 # There is no control to do for these attributes. They are attributes for the
44 # class management and not data of the model.
45 UNCHECKED_ATTRIBUTES = [
52 ## This class is a placeholder for modeling data. An object based on this class
53 # (particular instance or specialized derived class) can defined attributes with
54 # the following properties:
55 # - a type : the class or the type of the attribute. Setting an attribute to
56 # a value whose type is not the specified type raises an exception.
57 # - a range : a list of the possible values for the attribute. Setting an
58 # attribute to a value not in the range raises an exception
59 # - a default: the default value of an attribute when an instance is created
60 # - a void flag: the attribute can be authorized to be None or not using this
61 # flag. Setting an attribute to a None value while the flag is not set to
62 # True raises an exception. By default, a None value is not allowed.
64 # These properties are dictionnaries mapping the attribute name to its
65 # associated value for the property.
66 # \n A typical usage is to derived this class in a specialized form where the
67 # attributes names and there properties are defined in the constructor. See
68 # use cases at the end of this file.
69 # \ingroup datamodeler
72 This class is a placeholder for modeling data. An object based on this class
73 (particular instance or specialized derived class) can defined attributes with
74 the following properties:
76 - a type : the class or the type of the attribute. Setting an attribute to
77 a value whose type is not the specified type raises an exception.
78 - a range : a list of the possible values for the attribute. Setting an
79 attribute to a value not in the range raises an exception
80 - a default: the default value of an attribute when an instance is created
81 - a void flag: the attribute can be authorized to be None or not using this
82 flag. Setting an attribute to a None value while the flag is not set to
83 True raises an exception. By default, a None value is not allowed.
85 These properties are dictionnaries mapping the attribute name to its
86 associated value for the property.
88 A typical usage is to derived this class in a specialized form where the
89 attributes names and there properties are defined in the constructor. See
90 use cases at the end of this file.
93 def __init__(self, typemap=None, rangemap=None, defaultmap=None, voidmap=None):
95 self._rangemap = {} # possible values
96 self._defaultmap = {} # defaults values
97 self._voidmap = {} # None values are allowed
99 if typemap is not None:
100 self._typemap.update(typemap)
101 if rangemap is not None:
102 self._rangemap.update(rangemap)
103 if voidmap is not None:
104 self._voidmap.update(voidmap)
106 # Default initialization (if any)
107 if defaultmap is not None:
108 self._defaultmap.update(defaultmap)
109 for name in self._defaultmap:
110 self.__setattr__(name,self._defaultmap[name])
112 ## %A None argument means that no entry is created in the associated maps.
113 def addAttribute(self, name, a_type=None, a_range=None, default=None, void=None):
115 A None argument means that no entry is created in the associated maps.
117 self._typemap[name] = a_type
119 if a_range is not None:
120 self._rangemap[name] = a_range
123 self._voidmap[name] = void
125 if (not void) and (default is None):
128 self.__setattr__(name,default)
130 def __setattr__(self, name, val):
131 print (self, name, val)
132 if name in UNCHECKED_ATTRIBUTES:
133 #self.__dict__[name] = val
134 object.__setattr__(self, name, val)
138 if name == "_typemap":
139 print("WARNING WARNING WARNING : changing value of _typemap by ",val)
141 if name not in self._typemap:
142 raise DevelException("The class "+str(self.__class__)+" has no attribute "+str(name))
145 if not self.__isVoidAllowed(name):
146 raise DevelException("The attribute "+str(name)+" can't be None")
148 # We can stop here and set the value to None
149 self.__dict__[name] = None
152 if self.__isNotValidType(name,val):
153 raise DevelException("The attribute "+str(name)+" must be an instance of "+str(self._typemap[name]))
155 if self.__isNotValidRange(name,val):
156 raise DevelException("The attribute "+str(name)+" must be a value in :"+str(self._rangemap[name]))
158 self.__dict__[name] = val
160 def __getattribute__(self, name):
161 if name in UNCHECKED_ATTRIBUTES:
162 return object.__getattribute__(self, name)
164 if name in DataModeler.__dict__:
165 return object.__getattribute__(self, name)
168 #traceback.print_stack()
169 if name not in self._typemap:
170 raise DevelException("The class has no attribute "+str(name))
171 # The attribute coulb be requested while it has not been created yet (for
172 # example if we did't call the setter before).
173 if name not in self.__dict__.keys():
176 return object.__getattribute__(self, name)
182 def __isNotValidType(self, name, val):
184 ( self._typemap[name] is not None) and
185 ( not isinstance(val,self._typemap[name]) ) )
189 def __isNotValidRange(self, name, val):
191 ( self._rangemap is not None) and
192 ( name in self._rangemap ) and
193 ( self._rangemap[name] is not None ) and
194 ( val not in self._rangemap[name] ) )
198 def __isVoidAllowed(self,name):
200 ( self._voidmap is not None) and
201 ( name in self._voidmap ) and
202 ( self._voidmap[name] is True ) )
207 print("DATAMODELER ["+str(self.__class__)+"]: self._typemap.keys() = "+str(list(self._typemap.keys())))
213 # ==============================================================================
214 # Basic use cases and unit tests
215 # ==============================================================================
219 typemap["stringdata"] = TypeString
220 typemap["integerdata"] = TypeInteger
221 typemap["anydata"] = None # can be anything
223 data = DataModeler(typemap)
227 data.stringdata = sdata
228 data.integerdata = idata
231 data.anydata = "any value"
234 print(data.integerdata)
237 def TEST_addAttribute():
239 typemap["stringdata"] = TypeString
240 typemap["integerdata"] = TypeInteger
241 data = DataModeler(typemap)
242 data.stringdata = "a string value"
253 if data.myAttr != ref_value:
257 except Exception as e:
262 data.myAttr = "bad type value"
264 except Exception as e:
268 def TEST_badAttributeName():
270 map["stringdata"] = TypeString
271 map["integerdata"] = TypeInteger
273 data = DataModeler(map)
275 # this should raise an exception
279 except Exception as e:
280 print("OK : "+str(e))
283 def TEST_badAttributeType():
285 map["stringdata"] = TypeString
286 map["integerdata"] = TypeInteger
288 data = DataModeler(map)
289 # this should raise an exception
293 except Exception as e:
294 print("OK : "+str(e))
297 def TEST_badAttributeRange():
299 map["stringdata"] = TypeString
300 map["integerdata"] = TypeInteger
304 range["integerdata"] = [1,ref_integervalue,7]
306 data = DataModeler(map,range)
307 # this should not raise an exception
309 data.integerdata = ref_integervalue
310 data.stringdata = "anything (no restriction has been defined)"
311 except Exception as e:
315 # this should raise an exception
317 data.integerdata = 9999 # a value not in the range
319 except Exception as e:
323 def TEST_voidAttributeAllowed():
325 map["stringdata"] = TypeString
326 map["integerdata"] = TypeInteger
329 voidmap["stringdata"] = True
331 data = DataModeler(typemap=map,voidmap=voidmap)
333 # this should not raise an exception
334 data.stringdata = None
335 print(data.stringdata)
336 except Exception as e:
341 # this should raise an exception
342 data.integerdata = None
344 except Exception as e:
348 def TEST_defaultValues():
350 typemap["stringdata"] = TypeString
351 typemap["integerdata"] = TypeInteger
353 ref_value = "my initial value"
355 defaultmap["stringdata"] = ref_value
357 data = DataModeler(typemap=typemap,defaultmap=defaultmap)
358 print(data.stringdata)
359 if data.stringdata != ref_value:
364 if __name__ == "__main__":
365 from .unittester import run
366 run("salome/kernel/datamodeler","TEST_usecase")
367 run("salome/kernel/datamodeler","TEST_addAttribute")
368 run("salome/kernel/datamodeler","TEST_badAttributeName")
369 run("salome/kernel/datamodeler","TEST_badAttributeType")
370 run("salome/kernel/datamodeler","TEST_badAttributeRange")
371 run("salome/kernel/datamodeler","TEST_voidAttributeAllowed")
372 run("salome/kernel/datamodeler","TEST_defaultValues")