2 Ce module contient la classe mixin MCSIMP qui porte les méthodes
3 nécessaires pour réaliser la validation d'un objet de type MCSIMP
6 Une classe mixin porte principalement des traitements et est
7 utilisée par héritage multiple pour composer les traitements.
14 from Noyau import N_CR
15 from Noyau.N_Exception import AsException
20 Cette classe est quasiment identique à la classe originale d'EFICAS
21 a part quelques changements cosmétiques et des chagements pour la
22 faire fonctionner de facon plus autonome par rapport à l'environnement
25 A mon avis, il faudrait aller plus loin et réduire les dépendances
26 amont au strict nécessaire.
28 - Est il indispensable de faire l'évaluation de la valeur dans le contexte
29 du jdc dans cette classe.
31 - Ne pourrait on pas doter les objets en présence des méthodes suffisantes
32 pour éviter les tests un peu particuliers sur GEOM, PARAMETRE et autres. J'ai
33 d'ailleurs modifié la classe pour éviter l'import de GEOM
39 self.state='undetermined'
41 def isvalid(self,cr='non'):
43 Cette méthode retourne un indicateur de validité de l'objet
46 - 0 si l'objet est invalide
48 - 1 si l'objet est valide
50 Le pramètre cr permet de paramétrer le traitement. Si cr == 'oui'
51 la méthode construit également un comte-rendu de validation
52 dans self.cr qui doit avoir été créé préalablement.
54 if self.state == 'unchanged':
58 if hasattr(self,'valid'):
59 old_valid = self.valid
64 if self.isoblig() and v == None :
66 self.cr.fatal(string.join(("Mot-clé : ",self.nom," obligatoire non valorisé")))
69 valid = self.verif_type(cr=cr)*self.verif_into(cr=cr)*self.verif_card(cr=cr)
71 self.state = 'unchanged'
72 # Si la validité du mot clé a changé, on le signale à l'objet parent
74 if old_valid != self.valid : self.init_modif_up()
78 """ indique si le mot-clé est obligatoire
80 return self.definition.statut=='o'
82 def verif_card(self,cr='non'):
84 un mot-clé simple ne peut être répété :
85 la cardinalité ici s'entend par la vérification que le nombre d'arguments de self.valeur
86 est bien compris entre self.min et self.max dans le cas où il s'agit d'une liste
89 min=self.definition.min
90 max=self.definition.max
91 if type(self.valeur) in (types.ListType,types.TupleType) and 'C' not in self.definition.type :
92 if len(self.valeur) < min or len(self.valeur)>max:
94 self.cr.fatal("Nombre d'arguments %s incorrects pour %s (min = %s, max = %s)" %(`self.valeur`,self.nom,min,max))
97 if self.valeur == None :
99 # on n'a pas d'objet et on en attend au moins un
103 # on n'a qu'un objet et on en attend plus d'1
107 def verif_type(self,val=None,cr='non'):
110 Cette méthode a plusieurs modes de fonctionnement liés à la valeur de val et de cr.
111 Si cr ne vaut pas 'oui' : elle ne remplit pas le compte-rendu self.cr
112 Si val vaut None, elle vérifie le type de self.valeur
113 Si val ne vaut pas None, elle vérifie le type de val
114 PARAMETRE DE RETOUR :
115 Cette méthode retourne une valeur booléenne qui vaut 1 si le type est correct ou 0 sinon
124 self.cr.fatal("None n'est pas une valeur autorisée")
126 if type(valeur) == types.TupleType:
127 # on peut avoir à faire à un complexe ou une liste de valeurs ...
128 if self.is_complexe(valeur) : return 1
131 if not self.verif_type(val=val,cr=cr) : return 0
133 elif type(valeur) == types.ListType:
135 if not self.verif_type(val=val,cr=cr) : return 0
138 # on n'a pas de tuple ...il faut tester sur tous les types ou les valeurs possibles
139 # XXX Pourquoi into est il traité ici et pas seulement dans verif_into ???
140 if self.definition.into != None :
142 if valeur in self.definition.into :
146 self.cr.fatal("%s n'est pas une valeur autorisée" %valeur)
149 print "problème avec :",self.nom
150 print 'valeur =',valeur
152 for type_permis in self.definition.type:
153 if self.compare_type(valeur,type_permis) : return 1
154 # si on sort de la boucle précédente par ici c'est que l'on n'a trouvé aucun type valable --> valeur refusée
156 self.cr.fatal("%s n'est pas d'un type autorisé" %`valeur`)
159 def verif_into(self,cr='non'):
161 Vérifie si la valeur de self est bien dans l'ensemble discret de valeurs
162 donné dans le catalogue derrière l'attribut into ou vérifie que valeur est bien compris
163 entre val_min et val_max
165 if self.definition.into == None :
166 #on est dans le cas d'un ensemble continu de valeurs possibles (intervalle)
167 if type(self.valeur)==types.TupleType :
169 for val in self.valeur :
170 if type(val)!=types.StringType and type(val)!=types.InstanceType:
171 test = test*self.isinintervalle(val,cr=cr)
175 if type(val)!=types.StringType and type(val)!=types.InstanceType:
176 return self.isinintervalle(self.valeur,cr=cr)
180 # on est dans le cas d'un ensemble discret de valeurs possibles (into)
181 if type(self.valeur) == types.TupleType :
182 for e in self.valeur:
183 if e not in self.definition.into:
185 self.cr.fatal(string.join(("La valeur :",`e`," n'est pas permise pour le mot-clé :",self.nom)))
188 if self.valeur == None or self.valeur not in self.definition.into:
190 self.cr.fatal(string.join(("La valeur :",`self.valeur`," n'est pas permise pour le mot-clé :",self.nom)))
194 def is_complexe(self,valeur):
195 """ Retourne 1 si valeur est un complexe, 0 sinon """
196 if type(valeur) == types.StringType :
197 # on teste une valeur issue d'une entry (valeur saisie depuis EFICAS)
198 #XXX Il serait peut etre plus judicieux d'appeler une méthode de self.jdc
199 #XXX qui retournerait l'objet résultat de l'évaluation
200 #XXX ou meme de faire cette evaluation a l'exterieur de cette classe ??
201 if not self.jdc :return 0
203 valeur = eval(valeur,self.jdc.g_context)
206 if type(valeur) == types.InstanceType :
207 #XXX je n'y touche pas pour ne pas tout casser mais il serait
208 #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('C'), par exemple
209 if valeur.__class__.__name__ in ('EVAL','complexe'):
211 elif valeur.__class__.__name__ in ('PARAMETRE','PARAMETRE_EVAL'):
212 # il faut tester si la valeur du parametre est un entier
213 #XXX ne serait ce pas plutot complexe ???? sinon expliquer
214 return self.is_entier(valeur.valeur)
216 print "Objet non reconnu dans is_complexe %s" %`valeur`
218 elif type(valeur) != types.TupleType :
221 if len(valeur) != 3 :
224 if type(valeur[0]) != types.StringType : return 0
225 if string.strip(valeur[0]) not in ('RI','MP'):
228 if not self.is_reel(valeur[1]) or not self.is_reel(valeur[2]) : return 0
231 def is_reel(self,valeur):
233 Retourne 1 si valeur est un reel, 0 sinon
235 if type(valeur) == types.StringType :
236 # on teste une valeur issue d'une entry (valeur saisie depuis EFICAS)
237 if not self.jdc :return 0
239 valeur = eval(valeur,self.jdc.g_context)
242 if type(valeur) == types.InstanceType :
243 #XXX je n'y touche pas pour ne pas tout casser mais il serait
244 #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('R'), par exemple
245 #XXX ou valeur.is_reel()
246 #XXX ou encore valeur.compare(self.is_reel)
247 if valeur.__class__.__name__ in ('EVAL','reel') :
249 elif valeur.__class__.__name__ in ('PARAMETRE','PARAMETRE_EVAL'):
250 # il faut tester si la valeur du parametre est un réel
251 return self.is_reel(valeur.valeur)
253 print "Objet non reconnu dans is_reel %s" %`valeur`
255 elif type(valeur) not in (types.IntType,types.FloatType,types.LongType):
256 # ce n'est pas un réel
261 def is_entier(self,valeur):
262 """ Retourne 1 si valeur est un entier, 0 sinon """
263 if type(valeur) == types.StringType :
264 # on teste une valeur issue d'une entry (valeur saisie depuis EFICAS)
265 if not self.jdc :return 0
267 valeur = eval(valeur,self.jdc.g_context)
270 if type(valeur) == types.InstanceType :
271 #XXX je n'y touche pas pour ne pas tout casser mais il serait
272 #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('I'), par exemple
273 if valeur.__class__.__name__ in ('EVAL','entier') :
275 elif valeur.__class__.__name__ in ('PARAMETRE','PARAMETRE_EVAL'):
276 # il faut tester si la valeur du parametre est un entier
277 return self.is_entier(valeur.valeur)
279 print "Objet non reconnu dans is_reel %s" %`valeur`
281 elif type(valeur) not in (types.IntType,types.LongType):
282 # ce n'est pas un entier
287 def is_shell(self,valeur):
289 Retourne 1 si valeur est un shell, 0 sinon
290 Pour l'instant aucune vérification n'est faite
291 On impose juste que valeur soit une string
293 if type(valeur) != types.StringType:
298 def is_object_from(self,objet,classe):
300 Retourne 1 si valeur est un objet de la classe classe ou d'une sous-classe de classe,
303 if type(objet) != types.InstanceType :
304 if type(objet) == types.StringType:
305 if not self.jdc :return 0
307 objet = eval(objet,self.jdc.g_context)
308 if type(objet) != types.InstanceType : return 0
313 if not objet.__class__ == classe and not issubclass(objet.__class__,classe):
318 def compare_type(self,valeur,type_permis):
320 Fonction booléenne qui retourne 1 si valeur est du type type_permis, 0 sinon
322 if type(valeur) == types.InstanceType and valeur.__class__.__name__ == 'PARAMETRE':
323 if type(valeur.valeur) == types.TupleType :
324 # on a à faire à un PARAMETRE qui définit une liste d'items
325 # --> on teste sur la première car on n'accepte que les liste homogènes
326 valeur = valeur.valeur[0]
327 if type_permis == 'R':
328 return self.is_reel(valeur)
329 elif type_permis == 'I':
330 return self.is_entier(valeur)
331 elif type_permis == 'C':
332 return self.is_complexe(valeur)
333 elif type_permis == 'shell':
334 return self.is_shell(valeur)
335 elif type_permis == 'TXM':
336 if type(valeur) != types.InstanceType:
337 return type(valeur)==types.StringType
339 #XXX je n'y touche pas pour ne pas tout casser mais il serait
340 #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('TXM'), par exemple
341 if valeur.__class__.__name__ == 'chaine' :
343 elif valeur.__class__.__name__ == 'PARAMETRE':
344 # il faut tester si la valeur du parametre est une string
345 return type(valeur.valeur)==types.StringType
348 elif type(type_permis) == types.ClassType:
349 # on ne teste pas certains objets de type GEOM , assd, ...
350 # On appelle la méthode de classe is_object de type_permis.
351 # Comme valeur peut etre de n'importe quel type on utilise la fonction (is_object.im_func)
352 # et non pas la methode (is_object) ce qui risquerait de provoquer des erreurs
353 if type_permis.is_object.im_func(valeur):
356 return self.is_object_from(valeur,type_permis)
358 print "Type non encore géré %s" %`type_permis`
359 print self.nom,self.parent.nom,self.jdc.fichier
361 def isinintervalle(self,valeur,cr='non'):
363 Booléenne qui retourne 1 si la valeur passée en argument est comprise dans
364 le domaine de définition donné dans le catalogue, 0 sinon.
366 if type(valeur) not in (types.IntType,types.FloatType,types.LongType) :
369 min = self.definition.val_min
370 max = self.definition.val_max
371 if min == '**': min = valeur -1
372 if max == '**': max = valeur +1
373 if valeur < min or valeur > max :
375 self.cr.fatal(string.join(("La valeur :",`valeur`," du mot-clé ",self.nom,\
376 " est en dehors du domaine de validité [",`min`,",",`max`,"]")))
381 def init_modif_up(self):
383 Propage l'état modifié au parent s'il existe et n'est l'objet
386 if self.parent and self.parent != self :
387 self.parent.state = 'modified'
390 """ génère le rapport de validation de self """
392 self.cr.debut = "Mot-clé simple : "+self.nom
393 self.cr.fin = "Fin Mot-clé simple : "+self.nom
394 self.state = 'modified'
396 self.isvalid(cr='oui')
397 except AsException,e:
398 if CONTEXT.debug : traceback.print_exc()
399 self.cr.fatal(string.join(("Mot-clé simple : ",self.nom,str(e))))