Salome HOME
077069aaebd0a995c785e4db2ea33f113562fab1
[tools/eficas.git] / Validation / V_MCSIMP.py
1 #@ MODIF V_MCSIMP Validation  DATE 06/10/2003   AUTEUR DURAND C.DURAND 
2 #            CONFIGURATION MANAGEMENT OF EDF VERSION
3 # ======================================================================
4 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
5 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
6 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
7 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR   
8 # (AT YOUR OPTION) ANY LATER VERSION.                                 
9 #
10 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT 
11 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF          
12 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU    
13 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.                            
14 #
15 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE   
16 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,       
17 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.      
18 #                                                                       
19 #                                                                       
20 # ======================================================================
21 """
22    Ce module contient la classe mixin MCSIMP qui porte les méthodes
23    nécessaires pour réaliser la validation d'un objet de type MCSIMP
24    dérivé de OBJECT.
25
26    Une classe mixin porte principalement des traitements et est
27    utilisée par héritage multiple pour composer les traitements.
28 """
29 # Modules Python
30 import string,types
31 import traceback
32
33 # Modules EFICAS
34 from Noyau import N_CR
35 from Noyau.N_Exception import AsException
36
37 class MCSIMP:
38    """
39       COMMENTAIRE CCAR
40         Cette classe est quasiment identique à la classe originale d'EFICAS
41         a part quelques changements cosmétiques et des chagements pour la
42         faire fonctionner de facon plus autonome par rapport à l'environnement
43         EFICAS
44  
45         A mon avis, il faudrait aller plus loin et réduire les dépendances
46         amont au strict nécessaire.
47
48         - Est il indispensable de faire l'évaluation de la valeur dans le contexte
49           du jdc dans cette classe.
50
51         - Ne pourrait on pas doter les objets en présence des méthodes suffisantes
52           pour éviter les tests un peu particuliers sur GEOM, PARAMETRE et autres. J'ai
53           d'ailleurs modifié la classe pour éviter l'import de GEOM
54    """
55
56    CR=N_CR.CR
57    
58    def __init__(self):
59       self.state='undetermined'
60
61    def isvalid(self,cr='non'):
62       """
63          Cette méthode retourne un indicateur de validité de l'objet
64          de type MCSIMP 
65          
66          - 0 si l'objet est invalide
67  
68          - 1 si l'objet est valide
69
70          Le pramètre cr permet de paramétrer le traitement. Si cr == 'oui'
71          la méthode construit également un comte-rendu de validation
72          dans self.cr qui doit avoir été créé préalablement.
73       """
74       if self.state == 'unchanged':
75         return self.valid
76       else:
77         valid = 1
78         if hasattr(self,'valid'):
79           old_valid = self.valid
80         else:
81           old_valid = None
82         v=self.valeur
83         #  presence
84         if self.isoblig() and v == None :
85           if cr == 'oui' :
86             self.cr.fatal(string.join(("Mot-clé : ",self.nom," obligatoire non valorisé")))
87           valid = 0
88         if v is None:
89            if cr == 'oui' :
90               self.cr.fatal("None n'est pas une valeur autorisée")
91            valid=0
92         else:
93            # type,into ...
94            valid = self.verif_type(val=v,cr=cr)*self.verif_into(cr=cr)*self.verif_card(cr=cr)
95            #
96            # On verifie les validateurs s'il y en a
97            #
98            if self.definition.validators and not self.definition.validators.verif(self.valeur):
99               if cr == 'oui' :
100                  self.cr.fatal(string.join(("Mot-clé : ",self.nom,"devrait avoir ",self.definition.validators.info())))
101               valid=0
102            # fin des validateurs
103            #
104         self.valid = valid
105         self.state = 'unchanged'
106         # Si la validité du mot clé a changé, on le signale à l'objet parent
107         if not old_valid or old_valid != self.valid : 
108            self.init_modif_up()
109         return self.valid
110
111    def isoblig(self):
112       """ indique si le mot-clé est obligatoire
113       """
114       return self.definition.statut=='o'
115
116    def verif_card(self,cr='non'):
117       """ 
118          un mot-clé simple ne peut etre répété :
119            la cardinalité ici s'entend par la vérification que le nombre d'arguments de self.valeur
120            est bien compris entre self.min et self.max dans le cas où il s'agit d'une liste
121       """
122       card = 1
123       min=self.definition.min
124       max=self.definition.max
125       if type(self.valeur) in (types.ListType,types.TupleType) and 'C' not in self.definition.type :
126         if len(self.valeur) < min or len(self.valeur)>max:
127           if cr == 'oui':
128             self.cr.fatal("Nombre d'arguments %s incorrects pour %s (min = %s, max = %s)" %(`self.valeur`,self.nom,min,max))
129           card = 0
130       else:
131         if self.valeur == None :
132           if min >= 1 :
133             # on n'a pas d'objet et on en attend au moins un
134             card=0
135         else :
136           if min > 1:
137             # on n'a qu'un objet et on en attend plus d'1
138             card = 0
139       return card
140
141    def verif_type(self,val=None,cr='non'):
142       """
143         FONCTION :
144          Cette methode verifie que le type de l'argument val est en conformite avec celui 
145          qui est declare dans la definition du mot cle simple.
146          Elle a plusieurs modes de fonctionnement liés à la valeur de cr.
147          Si cr vaut 'oui' : elle remplit le compte-rendu self.cr sinon elle ne le remplit pas.
148         PARAMETRE DE RETOUR :
149          Cette méthode retourne une valeur booléenne qui vaut 1 si le type de val est correct ou 0 sinon
150          
151       """
152       valeur = val
153       if valeur == None :
154         if cr == 'oui':
155           self.cr.fatal("None n'est pas une valeur autorisée")
156         return 0
157       if type(valeur) == types.TupleType:
158         # on peut avoir à faire à un complexe ou une liste de valeurs ...
159         if self.is_complexe(valeur) : return 1
160         else:
161           for val in valeur:
162             if not self.verif_type(val=val,cr=cr) : return 0
163           return 1
164       elif type(valeur) == types.ListType:
165         for val in valeur:
166             if not self.verif_type(val=val,cr=cr) : return 0
167         return 1
168       else:
169         # on n'a pas de tuple ...il faut tester sur tous les types ou les valeurs possibles
170         # XXX Pourquoi into est il traité ici et pas seulement dans verif_into ???
171         if self.definition.into != None :
172           try:
173             if valeur in self.definition.into :
174               return 1
175             else:
176               if cr == 'oui':
177                 self.cr.fatal("%s n'est pas une valeur autorisée" %valeur)
178               return 0
179           except:
180             print "problème avec :",self.nom
181             print 'valeur =',valeur
182             return 0
183         for type_permis in self.definition.type:
184           if self.compare_type(valeur,type_permis) : return 1
185         # 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
186         if cr =='oui':
187           self.cr.fatal("%s n'est pas d'un type autorisé" %`valeur`)
188         return 0
189
190    def verif_into(self,cr='non'):
191       """
192       Vérifie si la valeur de self est bien dans l'ensemble discret de valeurs
193       donné dans le catalogue derrière l'attribut into ou vérifie que valeur est bien compris
194       entre val_min et val_max
195       """
196       if self.definition.into == None :
197         #on est dans le cas d'un ensemble continu de valeurs possibles (intervalle)
198         if type(self.valeur)==types.TupleType :
199           test = 1
200           for val in self.valeur :
201             if type(val)!=types.StringType and type(val)!=types.InstanceType:
202               test = test*self.isinintervalle(val,cr=cr)
203           return test
204         else :
205           val = self.valeur
206           if type(val)!=types.StringType and type(val)!=types.InstanceType:
207             return self.isinintervalle(self.valeur,cr=cr)
208           else :
209             return 1
210       else :
211         # on est dans le cas d'un ensemble discret de valeurs possibles (into)
212         # PN : pour résoudre le pb du copier /coller de la liste Ordonnee
213         # if type(self.valeur) == types.TupleType :
214         if type(self.valeur) in (types.ListType,types.TupleType) :
215           for e in self.valeur:
216             if e not in self.definition.into:
217               if cr=='oui':
218                 self.cr.fatal(string.join(("La valeur :",`e`," n'est pas permise pour le mot-clé :",self.nom)))
219               return 0
220         else:
221           if self.valeur == None or self.valeur not in self.definition.into:
222             if cr=='oui':
223               self.cr.fatal(string.join(("La valeur :",`self.valeur`," n'est pas permise pour le mot-clé :",self.nom)))
224             return 0
225         return 1
226
227    def is_complexe(self,valeur):
228       """ Retourne 1 si valeur est un complexe, 0 sinon """
229       if type(valeur) == types.StringType :
230         # on teste une valeur issue d'une entry (valeur saisie depuis EFICAS)
231         #XXX Il serait peut etre plus judicieux d'appeler une méthode de self.jdc
232         #XXX qui retournerait l'objet résultat de l'évaluation
233         #XXX ou meme de faire cette evaluation a l'exterieur de cette classe ??
234         if not self.jdc :return 0
235         try :
236           valeur = eval(valeur,self.jdc.g_context)
237         except:
238           return 0
239       if type(valeur) == types.InstanceType :
240         #XXX je n'y touche pas pour ne pas tout casser mais il serait
241         #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('C'), par exemple
242         if valeur.__class__.__name__ in ('EVAL','complexe'):
243           return 1
244         elif valeur.__class__.__name__ in ('PARAMETRE','PARAMETRE_EVAL'):
245           # il faut tester si la valeur du parametre est un entier
246           #XXX ne serait ce pas plutot complexe ???? sinon expliquer
247           return self.is_entier(valeur.valeur)
248         else:
249           print "Objet non reconnu dans is_complexe %s" %`valeur`
250           return 0
251       # Pour permettre l'utilisation de complexes Python
252       #elif type(valeur) == types.ComplexType:
253         #return 1
254       elif type(valeur) != types.TupleType :
255         return 0
256       else:
257         if len(valeur) != 3 :
258           return 0
259         else:
260           if type(valeur[0]) != types.StringType : return 0
261           if string.strip(valeur[0]) not in ('RI','MP'):
262             return 0
263           else:
264             if not self.is_reel(valeur[1]) or not self.is_reel(valeur[2]) : return 0
265             else: return 1
266
267    def is_reel(self,valeur):
268       """
269       Retourne 1 si valeur est un reel, 0 sinon
270       """
271       if type(valeur) == types.StringType :
272         # on teste une valeur issue d'une entry (valeur saisie depuis EFICAS)
273         if not self.jdc :return 0
274         try :
275           valeur = eval(valeur,self.jdc.g_context)
276         except:
277           return 0
278       if type(valeur) == types.InstanceType :
279         #XXX je n'y touche pas pour ne pas tout casser mais il serait
280         #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('R'), par exemple
281         #XXX ou valeur.is_reel()
282         #XXX ou encore valeur.compare(self.is_reel)
283         if valeur.__class__.__name__ in ('EVAL','reel') :
284           return 1
285         elif valeur.__class__.__name__ in ('PARAMETRE','PARAMETRE_EVAL'):
286           # il faut tester si la valeur du parametre est un réel
287           return self.is_reel(valeur.valeur)
288         else:
289           print "Objet non reconnu dans is_reel %s" %`valeur`
290           return 0
291       elif type(valeur) not in (types.IntType,types.FloatType,types.LongType):
292         # ce n'est pas un réel
293         return 0
294       else:
295         return 1
296
297    def is_entier(self,valeur):
298       """ Retourne 1 si valeur est un entier, 0 sinon """
299       if type(valeur) == types.StringType :
300         # on teste une valeur issue d'une entry (valeur saisie depuis EFICAS)
301         if not self.jdc :return 0
302         try :
303           valeur = eval(valeur,self.jdc.g_context)
304         except:
305           return 0
306       if type(valeur) == types.InstanceType :
307         #XXX je n'y touche pas pour ne pas tout casser mais il serait
308         #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('I'), par exemple
309         if valeur.__class__.__name__ in ('EVAL','entier') :
310           return 1
311         elif valeur.__class__.__name__ in ('PARAMETRE','PARAMETRE_EVAL'):
312           # il faut tester si la valeur du parametre est un entier
313           return self.is_entier(valeur.valeur)
314         else:
315           print "Objet non reconnu dans is_reel %s" %`valeur`
316           return 0
317       elif type(valeur) not in (types.IntType,types.LongType):
318         # ce n'est pas un entier
319         return 0
320       else:
321         return 1
322         
323    def is_shell(self,valeur):
324       """ 
325           Retourne 1 si valeur est un shell, 0 sinon
326           Pour l'instant aucune vérification n'est faite
327           On impose juste que valeur soit une string
328       """
329       if type(valeur) != types.StringType:
330         return 0
331       else:
332         return 1
333
334    def is_object_from(self,objet,classe):
335       """ 
336            Retourne 1 si valeur est un objet de la classe classe ou d'une sous-classe de classe,
337            0 sinon 
338       """
339       if type(objet) != types.InstanceType :
340         if type(objet) == types.StringType:
341           if not self.jdc :return 0
342           try :
343             objet = eval(objet,self.jdc.g_context)
344             if type(objet) != types.InstanceType : return 0
345           except:
346             return 0
347         else:
348           return 0
349       if not objet.__class__ == classe and not issubclass(objet.__class__,classe):
350         return 0
351       else:
352         return 1
353
354    def compare_type(self,valeur,type_permis):
355       """
356           Fonction booléenne qui retourne 1 si valeur est du type type_permis, 0 sinon
357       """
358       if type(valeur) == types.InstanceType and valeur.__class__.__name__ == 'PARAMETRE':
359         if type(valeur.valeur) == types.TupleType :
360           # on a à faire à un PARAMETRE qui définit une liste d'items
361           # --> on teste sur la première car on n'accepte que les liste homogènes
362           valeur = valeur.valeur[0]
363       if type_permis == 'R':
364         return self.is_reel(valeur)
365       elif type_permis == 'I':
366         return self.is_entier(valeur)
367       elif type_permis == 'C':
368         return self.is_complexe(valeur)
369       elif type_permis == 'shell':
370         return self.is_shell(valeur)
371       elif type_permis == 'TXM':
372         if type(valeur) != types.InstanceType:
373           return type(valeur)==types.StringType
374         else:
375           #XXX je n'y touche pas pour ne pas tout casser mais il serait
376           #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('TXM'), par exemple
377           if valeur.__class__.__name__ == 'chaine' :
378             return 1
379           elif valeur.__class__.__name__ == 'PARAMETRE':
380             # il faut tester si la valeur du parametre est une string
381             return type(valeur.valeur)==types.StringType
382           else:
383             return 0
384       elif type(type_permis) == types.ClassType:
385         # on ne teste pas certains objets de type GEOM , assd, ...
386         # On appelle la méthode de classe is_object de type_permis.
387         # Comme valeur peut etre de n'importe quel type on utilise la fonction (is_object.im_func)
388         # et non pas la methode (is_object) ce qui risquerait de provoquer des erreurs
389         if type_permis.is_object.im_func(valeur):
390           return 1
391         else :
392           return self.is_object_from(valeur,type_permis)
393       else:
394         print "Type non encore géré %s" %`type_permis`
395         print self.nom,self.parent.nom,self.jdc.fichier
396
397    def isinintervalle(self,valeur,cr='non'):
398       """
399       Booléenne qui retourne 1 si la valeur passée en argument est comprise dans
400       le domaine de définition donné dans le catalogue, 0 sinon.
401       """
402       if type(valeur) not in (types.IntType,types.FloatType,types.LongType) :
403         return 1
404       else :
405         min = self.definition.val_min
406         max = self.definition.val_max
407         if min == '**': min = valeur -1
408         if max == '**': max = valeur +1
409         if valeur < min or valeur > max :
410           if cr=='oui':
411             self.cr.fatal(string.join(("La valeur :",`valeur`," du mot-clé ",self.nom,\
412                                        " est en dehors du domaine de validité [",`min`,",",`max`,"]")))
413           return 0
414         else :
415           return 1
416
417    def init_modif_up(self):
418       """
419          Propage l'état modifié au parent s'il existe et n'est l'objet 
420          lui-meme
421       """
422       if self.parent and self.parent != self :
423         self.parent.state = 'modified'
424
425    def report(self):
426       """ génère le rapport de validation de self """
427       self.cr=self.CR()
428       self.cr.debut = "Mot-clé simple : "+self.nom
429       self.cr.fin = "Fin Mot-clé simple : "+self.nom
430       self.state = 'modified'
431       try:
432         self.isvalid(cr='oui')
433       except AsException,e:
434         if CONTEXT.debug : traceback.print_exc()
435         self.cr.fatal(string.join(("Mot-clé simple : ",self.nom,str(e))))
436       return self.cr
437
438
439
440
441
442