Salome HOME
c1d0da958d50e3425ceb973e06eb089af7a94d69
[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         if self.is_complexe(valeur) : return 1
166         for val in valeur:
167             if not self.verif_type(val=val,cr=cr) : return 0
168         return 1
169       else:
170         # on n'a pas de tuple ...il faut tester sur tous les types ou les valeurs possibles
171         # XXX Pourquoi into est il traité ici et pas seulement dans verif_into ???
172         if self.definition.into != None :
173           try:
174             if valeur in self.definition.into :
175               return 1
176             else:
177               if cr == 'oui':
178                 self.cr.fatal("%s n'est pas une valeur autorisée" %valeur)
179               return 0
180           except:
181             print "problème avec :",self.nom
182             print 'valeur =',valeur
183             return 0
184         for type_permis in self.definition.type:
185           if self.compare_type(valeur,type_permis) : return 1
186         # 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
187         if cr =='oui':
188           self.cr.fatal("%s n'est pas d'un type autorisé" %`valeur`)
189         return 0
190
191    def verif_into(self,cr='non'):
192       """
193       Vérifie si la valeur de self est bien dans l'ensemble discret de valeurs
194       donné dans le catalogue derrière l'attribut into ou vérifie que valeur est bien compris
195       entre val_min et val_max
196       """
197       if self.definition.into == None :
198         #on est dans le cas d'un ensemble continu de valeurs possibles (intervalle)
199         if type(self.valeur)==types.TupleType :
200           test = 1
201           for val in self.valeur :
202             if type(val)!=types.StringType and type(val)!=types.InstanceType:
203               test = test*self.isinintervalle(val,cr=cr)
204           return test
205         else :
206           val = self.valeur
207           if type(val)!=types.StringType and type(val)!=types.InstanceType:
208             return self.isinintervalle(self.valeur,cr=cr)
209           else :
210             return 1
211       else :
212         # on est dans le cas d'un ensemble discret de valeurs possibles (into)
213         # PN : pour résoudre le pb du copier /coller de la liste Ordonnee
214         # if type(self.valeur) == types.TupleType :
215         if type(self.valeur) in (types.ListType,types.TupleType) :
216           for e in self.valeur:
217             if e not in self.definition.into:
218               if cr=='oui':
219                 self.cr.fatal(string.join(("La valeur :",`e`," n'est pas permise pour le mot-clé :",self.nom)))
220               return 0
221         else:
222           if self.valeur == None or self.valeur not in self.definition.into:
223             if cr=='oui':
224               self.cr.fatal(string.join(("La valeur :",`self.valeur`," n'est pas permise pour le mot-clé :",self.nom)))
225             return 0
226         return 1
227
228    def is_complexe(self,valeur):
229       """ Retourne 1 si valeur est un complexe, 0 sinon """
230       if type(valeur) == types.StringType :
231         # on teste une valeur issue d'une entry (valeur saisie depuis EFICAS)
232         #XXX Il serait peut etre plus judicieux d'appeler une méthode de self.jdc
233         #XXX qui retournerait l'objet résultat de l'évaluation
234         #XXX ou meme de faire cette evaluation a l'exterieur de cette classe ??
235         if not self.jdc :return 0
236         try :
237           valeur = eval(valeur,self.jdc.g_context)
238         except:
239           return 0
240       if type(valeur) == types.InstanceType :
241         #XXX je n'y touche pas pour ne pas tout casser mais il serait
242         #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('C'), par exemple
243         if valeur.__class__.__name__ in ('EVAL','complexe'):
244           return 1
245         elif valeur.__class__.__name__ in ('PARAMETRE','PARAMETRE_EVAL'):
246           # il faut tester si la valeur du parametre est un entier
247           #XXX ne serait ce pas plutot complexe ???? sinon expliquer
248           return self.is_entier(valeur.valeur)
249         else:
250           print "Objet non reconnu dans is_complexe %s" %`valeur`
251           return 0
252       # Pour permettre l'utilisation de complexes Python
253       #elif type(valeur) == types.ComplexType:
254         #return 1
255       elif type(valeur) != types.TupleType and  type(valeur) != types.ListType:
256         return 0
257       else:
258         if len(valeur) != 3 :
259           return 0
260         else:
261           if type(valeur[0]) != types.StringType : return 0
262           if string.strip(valeur[0]) not in ('RI','MP'):
263             return 0
264           else:
265             if not self.is_reel(valeur[1]) or not self.is_reel(valeur[2]) : return 0
266             else: return 1
267
268    def is_reel(self,valeur):
269       """
270       Retourne 1 si valeur est un reel, 0 sinon
271       """
272       if type(valeur) == types.StringType :
273         # on teste une valeur issue d'une entry (valeur saisie depuis EFICAS)
274         if not self.jdc :return 0
275         try :
276           valeur = eval(valeur,self.jdc.g_context)
277         except:
278           return 0
279       if type(valeur) == types.InstanceType :
280         #XXX je n'y touche pas pour ne pas tout casser mais il serait
281         #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('R'), par exemple
282         #XXX ou valeur.is_reel()
283         #XXX ou encore valeur.compare(self.is_reel)
284         if valeur.__class__.__name__ in ('EVAL','reel') :
285           return 1
286         elif valeur.__class__.__name__ in ('PARAMETRE','PARAMETRE_EVAL'):
287           # il faut tester si la valeur du parametre est un réel
288           return self.is_reel(valeur.valeur)
289         else:
290           print "Objet non reconnu dans is_reel %s" %`valeur`
291           return 0
292       elif type(valeur) not in (types.IntType,types.FloatType,types.LongType):
293         # ce n'est pas un réel
294         return 0
295       else:
296         return 1
297
298    def is_entier(self,valeur):
299       """ Retourne 1 si valeur est un entier, 0 sinon """
300       if type(valeur) == types.StringType :
301         # on teste une valeur issue d'une entry (valeur saisie depuis EFICAS)
302         if not self.jdc :return 0
303         try :
304           valeur = eval(valeur,self.jdc.g_context)
305         except:
306           return 0
307       if type(valeur) == types.InstanceType :
308         #XXX je n'y touche pas pour ne pas tout casser mais il serait
309         #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('I'), par exemple
310         if valeur.__class__.__name__ in ('EVAL','entier') :
311           return 1
312         elif valeur.__class__.__name__ in ('PARAMETRE','PARAMETRE_EVAL'):
313           # il faut tester si la valeur du parametre est un entier
314           return self.is_entier(valeur.valeur)
315         else:
316           print "Objet non reconnu dans is_reel %s" %`valeur`
317           return 0
318       elif type(valeur) not in (types.IntType,types.LongType):
319         # ce n'est pas un entier
320         return 0
321       else:
322         return 1
323         
324    def is_shell(self,valeur):
325       """ 
326           Retourne 1 si valeur est un shell, 0 sinon
327           Pour l'instant aucune vérification n'est faite
328           On impose juste que valeur soit une string
329       """
330       if type(valeur) != types.StringType:
331         return 0
332       else:
333         return 1
334
335    def is_object_from(self,objet,classe):
336       """ 
337            Retourne 1 si valeur est un objet de la classe classe ou d'une sous-classe de classe,
338            0 sinon 
339       """
340       if type(objet) != types.InstanceType :
341         if type(objet) == types.StringType:
342           if not self.jdc :return 0
343           try :
344             objet = eval(objet,self.jdc.g_context)
345             if type(objet) != types.InstanceType : return 0
346           except:
347             return 0
348         else:
349           return 0
350       if not objet.__class__ == classe and not issubclass(objet.__class__,classe):
351         return 0
352       else:
353         return 1
354
355    def compare_type(self,valeur,type_permis):
356       """
357           Fonction booléenne qui retourne 1 si valeur est du type type_permis, 0 sinon
358       """
359       if type(valeur) == types.InstanceType and valeur.__class__.__name__ == 'PARAMETRE':
360         if type(valeur.valeur) == types.TupleType :
361           # on a à faire à un PARAMETRE qui définit une liste d'items
362           # --> on teste sur la première car on n'accepte que les liste homogènes
363           valeur = valeur.valeur[0]
364       if type_permis == 'R':
365         return self.is_reel(valeur)
366       elif type_permis == 'I':
367         return self.is_entier(valeur)
368       elif type_permis == 'C':
369         return self.is_complexe(valeur)
370       elif type_permis == 'shell':
371         return self.is_shell(valeur)
372       elif type_permis == 'TXM':
373         if type(valeur) != types.InstanceType:
374           return type(valeur)==types.StringType
375         else:
376           #XXX je n'y touche pas pour ne pas tout casser mais il serait
377           #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('TXM'), par exemple
378           if valeur.__class__.__name__ == 'chaine' :
379             return 1
380           elif valeur.__class__.__name__ == 'PARAMETRE':
381             # il faut tester si la valeur du parametre est une string
382             return type(valeur.valeur)==types.StringType
383           else:
384             return 0
385       elif type(type_permis) == types.ClassType:
386         # on ne teste pas certains objets de type GEOM , assd, ...
387         # On appelle la méthode de classe is_object de type_permis.
388         # Comme valeur peut etre de n'importe quel type on utilise la fonction (is_object.im_func)
389         # et non pas la methode (is_object) ce qui risquerait de provoquer des erreurs
390         if type_permis.is_object.im_func(valeur):
391           return 1
392         else :
393           return self.is_object_from(valeur,type_permis)
394       else:
395         print "Type non encore géré %s" %`type_permis`
396         print self.nom,self.parent.nom,self.jdc.fichier
397
398    def isinintervalle(self,valeur,cr='non'):
399       """
400       Booléenne qui retourne 1 si la valeur passée en argument est comprise dans
401       le domaine de définition donné dans le catalogue, 0 sinon.
402       """
403       if type(valeur) not in (types.IntType,types.FloatType,types.LongType) :
404         return 1
405       else :
406         min = self.definition.val_min
407         max = self.definition.val_max
408         if min == '**': min = valeur -1
409         if max == '**': max = valeur +1
410         if valeur < min or valeur > max :
411           if cr=='oui':
412             self.cr.fatal(string.join(("La valeur :",`valeur`," du mot-clé ",self.nom,\
413                                        " est en dehors du domaine de validité [",`min`,",",`max`,"]")))
414           return 0
415         else :
416           return 1
417
418    def init_modif_up(self):
419       """
420          Propage l'état modifié au parent s'il existe et n'est l'objet 
421          lui-meme
422       """
423       if self.parent and self.parent != self :
424         self.parent.state = 'modified'
425
426    def report(self):
427       """ génère le rapport de validation de self """
428       self.cr=self.CR()
429       self.cr.debut = "Mot-clé simple : "+self.nom
430       self.cr.fin = "Fin Mot-clé simple : "+self.nom
431       self.state = 'modified'
432       try:
433         self.isvalid(cr='oui')
434       except AsException,e:
435         if CONTEXT.debug : traceback.print_exc()
436         self.cr.fatal(string.join(("Mot-clé simple : ",self.nom,str(e))))
437       return self.cr
438
439
440
441
442
443