1 # -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2010-2014 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__
42 # There is no control to do for these attributes. They are attributes for the
43 # class management and not data of the model.
44 UNCHECKED_ATTRIBUTES = [
51 ## This class is a placeholder for modeling data. An object based on this class
52 # (particular instance or specialized derived class) can defined attributes with
53 # the following properties:
54 # - a type : the class or the type of the attribute. Setting an attribute to
55 # a value whose type is not the specified type raises an exception.
56 # - a range : a list of the possible values for the attribute. Setting an
57 # attribute to a value not in the range raises an exception
58 # - a default: the default value of an attribute when an instance is created
59 # - a void flag: the attribute can be authorized to be None or not using this
60 # flag. Setting an attribute to a None value while the flag is not set to
61 # True raises an exception. By default, a None value is not allowed.
63 # These properties are dictionnaries mapping the attribute name to its
64 # associated value for the property.
65 # \n A typical usage is to derived this class in a specialized form where the
66 # attributes names and there properties are defined in the constructor. See
67 # use cases at the end of this file.
68 # \ingroup datamodeler
71 This class is a placeholder for modeling data. An object based on this class
72 (particular instance or specialized derived class) can defined attributes with
73 the following properties:
75 - a type : the class or the type of the attribute. Setting an attribute to
76 a value whose type is not the specified type raises an exception.
77 - a range : a list of the possible values for the attribute. Setting an
78 attribute to a value not in the range raises an exception
79 - a default: the default value of an attribute when an instance is created
80 - a void flag: the attribute can be authorized to be None or not using this
81 flag. Setting an attribute to a None value while the flag is not set to
82 True raises an exception. By default, a None value is not allowed.
84 These properties are dictionnaries mapping the attribute name to its
85 associated value for the property.
87 A typical usage is to derived this class in a specialized form where the
88 attributes names and there properties are defined in the constructor. See
89 use cases at the end of this file.
92 def __init__(self, typemap=None, rangemap=None, defaultmap=None, voidmap=None):
94 self._rangemap = {} # possible values
95 self._defaultmap = {} # defaults values
96 self._voidmap = {} # None values are allowed
98 if typemap is not None:
99 self._typemap.update(typemap)
100 if rangemap is not None:
101 self._rangemap.update(rangemap)
102 if voidmap is not None:
103 self._voidmap.update(voidmap)
105 # Default initialization (if any)
106 if defaultmap is not None:
107 self._defaultmap.update(defaultmap)
108 for name in self._defaultmap.keys():
109 self.__setattr__(name,self._defaultmap[name])
111 ## %A None argument means that no entry is created in the associated maps.
112 def addAttribute(self, name, type=None, range=None, default=None, void=None):
114 A None argument means that no entry is created in the associated maps.
116 self._typemap[name] = type
118 if range is not None:
119 self._rangemap[name] = range
122 self._voidmap[name] = void
124 if (not void) and (default is None):
127 self.__setattr__(name,default)
129 def __setattr__(self, name, val):
130 if name in UNCHECKED_ATTRIBUTES:
131 self.__dict__[name] = val
135 if name == "_typemap":
136 print "WARNING WARNING WARNING : changing value of _typemap by ",val
138 if name not in self._typemap.keys():
139 raise DevelException("The class "+str(self.__class__)+" has no attribute "+str(name))
142 if not self.__isVoidAllowed(name):
143 raise DevelException("The attribute "+str(name)+" can't be None")
145 # We can stop here and set the value to None
146 self.__dict__[name] = None
149 if self.__isNotValidType(name,val):
150 raise DevelException("The attribute "+str(name)+" must be an instance of "+str(self._typemap[name]))
152 if self.__isNotValidRange(name,val):
153 raise DevelException("The attribute "+str(name)+" must be a value in :"+str(self._rangemap[name]))
155 self.__dict__[name] = val
157 def __getattribute__(self, name):
158 if name in UNCHECKED_ATTRIBUTES:
159 return self.__dict__[name]
161 if name not in self._typemap.keys():
162 raise DevelException("The class "+str(self.__class__)+" has no attribute "+str(name))
163 # The attribute coulb be requested while it has not been created yet (for
164 # example if we did't call the setter before).
165 if not self.__dict__.has_key(name):
168 return self.__dict__[name]
170 def __isNotValidType(self, name, val):
172 ( self._typemap[name] is not None) and
173 ( not isinstance(val,self._typemap[name]) ) )
177 def __isNotValidRange(self, name, val):
179 ( self._rangemap is not None) and
180 ( self._rangemap.has_key(name) ) and
181 ( self._rangemap[name] is not None ) and
182 ( val not in self._rangemap[name] ) )
186 def __isVoidAllowed(self,name):
188 ( self._voidmap is not None) and
189 ( self._voidmap.has_key(name) ) and
190 ( self._voidmap[name] is True ) )
195 print "DATAMODELER ["+str(self.__class__)+"]: self._typemap.keys() = "+str(self._typemap.keys())
201 # ==============================================================================
202 # Basic use cases and unit tests
203 # ==============================================================================
207 typemap["stringdata"] = TypeString
208 typemap["integerdata"] = TypeInteger
209 typemap["anydata"] = None # can be anything
211 data = DataModeler(typemap)
215 data.stringdata = sdata
216 data.integerdata = idata
219 data.anydata = "any value"
222 print data.integerdata
225 def TEST_addAttribute():
227 typemap["stringdata"] = TypeString
228 typemap["integerdata"] = TypeInteger
229 data = DataModeler(typemap)
230 data.stringdata = "a string value"
241 if data.myAttr != ref_value:
250 data.myAttr = "bad type value"
256 def TEST_badAttributeName():
258 map["stringdata"] = TypeString
259 map["integerdata"] = TypeInteger
261 data = DataModeler(map)
263 # this should raise an exception
271 def TEST_badAttributeType():
273 map["stringdata"] = TypeString
274 map["integerdata"] = TypeInteger
276 data = DataModeler(map)
277 # this should raise an exception
285 def TEST_badAttributeRange():
287 map["stringdata"] = TypeString
288 map["integerdata"] = TypeInteger
292 range["integerdata"] = [1,ref_integervalue,7]
294 data = DataModeler(map,range)
295 # this should not raise an exception
297 data.integerdata = ref_integervalue
298 data.stringdata = "anything (no restriction has been defined)"
303 # this should raise an exception
305 data.integerdata = 9999 # a value not in the range
311 def TEST_voidAttributeAllowed():
313 map["stringdata"] = TypeString
314 map["integerdata"] = TypeInteger
317 voidmap["stringdata"] = True
319 data = DataModeler(typemap=map,voidmap=voidmap)
321 # this should not raise an exception
322 data.stringdata = None
323 print data.stringdata
329 # this should raise an exception
330 data.integerdata = None
336 def TEST_defaultValues():
338 typemap["stringdata"] = TypeString
339 typemap["integerdata"] = TypeInteger
341 ref_value = "my initial value"
343 defaultmap["stringdata"] = ref_value
345 data = DataModeler(typemap=typemap,defaultmap=defaultmap)
346 print data.stringdata
347 if data.stringdata != ref_value:
352 if __name__ == "__main__":
353 from unittester import run
354 run("salome/kernel/datamodeler","TEST_usecase")
355 run("salome/kernel/datamodeler","TEST_addAttribute")
356 run("salome/kernel/datamodeler","TEST_badAttributeName")
357 run("salome/kernel/datamodeler","TEST_badAttributeType")
358 run("salome/kernel/datamodeler","TEST_badAttributeRange")
359 run("salome/kernel/datamodeler","TEST_voidAttributeAllowed")
360 run("salome/kernel/datamodeler","TEST_defaultValues")