Salome HOME
b80e670d274b734a7cb7dbdaa015f849b899b63c
[tools/eficas.git] / Validation / V_MCSIMP.py
1 #@ MODIF V_MCSIMP Validation  DATE 20/01/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         # type,into ...
89         valid = self.verif_type(cr=cr)*self.verif_into(cr=cr)*self.verif_card(cr=cr)
90         self.valid = valid
91         self.state = 'unchanged'
92         # Si la validité du mot clé a changé, on le signale à l'objet parent
93         if old_valid:
94           if old_valid != self.valid : self.init_modif_up()
95         return self.valid
96
97    def isoblig(self):
98       """ indique si le mot-clé est obligatoire
99       """
100       return self.definition.statut=='o'
101
102    def verif_card(self,cr='non'):
103       """ 
104          un mot-clé simple ne peut etre répété :
105            la cardinalité ici s'entend par la vérification que le nombre d'arguments de self.valeur
106            est bien compris entre self.min et self.max dans le cas où il s'agit d'une liste
107       """
108       card = 1
109       min=self.definition.min
110       max=self.definition.max
111       if type(self.valeur) in (types.ListType,types.TupleType) and 'C' not in self.definition.type :
112         if len(self.valeur) < min or len(self.valeur)>max:
113           if cr == 'oui':
114             self.cr.fatal("Nombre d'arguments %s incorrects pour %s (min = %s, max = %s)" %(`self.valeur`,self.nom,min,max))
115           card = 0
116       else:
117         if self.valeur == None :
118           if min >= 1 :
119             # on n'a pas d'objet et on en attend au moins un
120             card=0
121         else :
122           if min > 1:
123             # on n'a qu'un objet et on en attend plus d'1
124             card = 0
125       return card
126
127    def verif_type(self,val=None,cr='non'):
128       """
129         FONCTION :
130          Cette méthode a plusieurs modes de fonctionnement liés à la valeur de val et de cr.
131          Si cr ne vaut pas 'oui' : elle ne remplit pas le compte-rendu self.cr
132          Si val vaut None, elle vérifie le type de self.valeur
133          Si val ne vaut pas None, elle vérifie le type de val
134         PARAMETRE DE RETOUR :
135          Cette méthode retourne une valeur booléenne qui vaut 1 si le type est correct ou 0 sinon
136          
137       """
138       if val != None:
139         valeur = val
140       else:
141         valeur = self.valeur
142       if valeur == None :
143         if cr == 'oui':
144           self.cr.fatal("None n'est pas une valeur autorisée")
145         return 0
146       if type(valeur) == types.TupleType:
147         # on peut avoir à faire à un complexe ou une liste de valeurs ...
148         if self.is_complexe(valeur) : return 1
149         else:
150           for val in valeur:
151             if not self.verif_type(val=val,cr=cr) : return 0
152           return 1
153       elif type(valeur) == types.ListType:
154         for val in valeur:
155             if not self.verif_type(val=val,cr=cr) : return 0
156         return 1
157       else:
158         # on n'a pas de tuple ...il faut tester sur tous les types ou les valeurs possibles
159         # XXX Pourquoi into est il traité ici et pas seulement dans verif_into ???
160         if self.definition.into != None :
161           try:
162             if valeur in self.definition.into :
163               return 1
164             else:
165               if cr == 'oui':
166                 self.cr.fatal("%s n'est pas une valeur autorisée" %valeur)
167               return 0
168           except:
169             print "problème avec :",self.nom
170             print 'valeur =',valeur
171             return 0
172         for type_permis in self.definition.type:
173           if self.compare_type(valeur,type_permis) : return 1
174         # 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
175         if cr =='oui':
176           self.cr.fatal("%s n'est pas d'un type autorisé" %`valeur`)
177         return 0
178
179    def verif_into(self,cr='non'):
180       """
181       Vérifie si la valeur de self est bien dans l'ensemble discret de valeurs
182       donné dans le catalogue derrière l'attribut into ou vérifie que valeur est bien compris
183       entre val_min et val_max
184       """
185       if self.definition.into == None :
186         #on est dans le cas d'un ensemble continu de valeurs possibles (intervalle)
187         if type(self.valeur)==types.TupleType :
188           test = 1
189           for val in self.valeur :
190             if type(val)!=types.StringType and type(val)!=types.InstanceType:
191               test = test*self.isinintervalle(val,cr=cr)
192           return test
193         else :
194           val = self.valeur
195           if type(val)!=types.StringType and type(val)!=types.InstanceType:
196             return self.isinintervalle(self.valeur,cr=cr)
197           else :
198             return 1
199       else :
200         # on est dans le cas d'un ensemble discret de valeurs possibles (into)
201         if type(self.valeur) == types.TupleType :
202           for e in self.valeur:
203             if e not in self.definition.into:
204               if cr=='oui':
205                 self.cr.fatal(string.join(("La valeur :",`e`," n'est pas permise pour le mot-clé :",self.nom)))
206               return 0
207         else:
208           if self.valeur == None or self.valeur not in self.definition.into:
209             if cr=='oui':
210               self.cr.fatal(string.join(("La valeur :",`self.valeur`," n'est pas permise pour le mot-clé :",self.nom)))
211             return 0
212         return 1
213
214    def is_complexe(self,valeur):
215       """ Retourne 1 si valeur est un complexe, 0 sinon """
216       if type(valeur) == types.StringType :
217         # on teste une valeur issue d'une entry (valeur saisie depuis EFICAS)
218         #XXX Il serait peut etre plus judicieux d'appeler une méthode de self.jdc
219         #XXX qui retournerait l'objet résultat de l'évaluation
220         #XXX ou meme de faire cette evaluation a l'exterieur de cette classe ??
221         if not self.jdc :return 0
222         try :
223           valeur = eval(valeur,self.jdc.g_context)
224         except:
225           return 0
226       if type(valeur) == types.InstanceType :
227         #XXX je n'y touche pas pour ne pas tout casser mais il serait
228         #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('C'), par exemple
229         if valeur.__class__.__name__ in ('EVAL','complexe'):
230           return 1
231         elif valeur.__class__.__name__ in ('PARAMETRE','PARAMETRE_EVAL'):
232           # il faut tester si la valeur du parametre est un entier
233           #XXX ne serait ce pas plutot complexe ???? sinon expliquer
234           return self.is_entier(valeur.valeur)
235         else:
236           print "Objet non reconnu dans is_complexe %s" %`valeur`
237           return 0
238       # Pour permettre l'utilisation de complexes Python
239       #elif type(valeur) == types.ComplexType:
240         #return 1
241       elif type(valeur) != types.TupleType :
242         return 0
243       else:
244         if len(valeur) != 3 :
245           return 0
246         else:
247           if type(valeur[0]) != types.StringType : return 0
248           if string.strip(valeur[0]) not in ('RI','MP'):
249             return 0
250           else:
251             if not self.is_reel(valeur[1]) or not self.is_reel(valeur[2]) : return 0
252             else: return 1
253
254    def is_reel(self,valeur):
255       """
256       Retourne 1 si valeur est un reel, 0 sinon
257       """
258       if type(valeur) == types.StringType :
259         # on teste une valeur issue d'une entry (valeur saisie depuis EFICAS)
260         if not self.jdc :return 0
261         try :
262           valeur = eval(valeur,self.jdc.g_context)
263         except:
264           return 0
265       if type(valeur) == types.InstanceType :
266         #XXX je n'y touche pas pour ne pas tout casser mais il serait
267         #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('R'), par exemple
268         #XXX ou valeur.is_reel()
269         #XXX ou encore valeur.compare(self.is_reel)
270         if valeur.__class__.__name__ in ('EVAL','reel') :
271           return 1
272         elif valeur.__class__.__name__ in ('PARAMETRE','PARAMETRE_EVAL'):
273           # il faut tester si la valeur du parametre est un réel
274           return self.is_reel(valeur.valeur)
275         else:
276           print "Objet non reconnu dans is_reel %s" %`valeur`
277           return 0
278       elif type(valeur) not in (types.IntType,types.FloatType,types.LongType):
279         # ce n'est pas un réel
280         return 0
281       else:
282         return 1
283
284    def is_entier(self,valeur):
285       """ Retourne 1 si valeur est un entier, 0 sinon """
286       if type(valeur) == types.StringType :
287         # on teste une valeur issue d'une entry (valeur saisie depuis EFICAS)
288         if not self.jdc :return 0
289         try :
290           valeur = eval(valeur,self.jdc.g_context)
291         except:
292           return 0
293       if type(valeur) == types.InstanceType :
294         #XXX je n'y touche pas pour ne pas tout casser mais il serait
295         #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('I'), par exemple
296         if valeur.__class__.__name__ in ('EVAL','entier') :
297           return 1
298         elif valeur.__class__.__name__ in ('PARAMETRE','PARAMETRE_EVAL'):
299           # il faut tester si la valeur du parametre est un entier
300           return self.is_entier(valeur.valeur)
301         else:
302           print "Objet non reconnu dans is_reel %s" %`valeur`
303           return 0
304       elif type(valeur) not in (types.IntType,types.LongType):
305         # ce n'est pas un entier
306         return 0
307       else:
308         return 1
309         
310    def is_shell(self,valeur):
311       """ 
312           Retourne 1 si valeur est un shell, 0 sinon
313           Pour l'instant aucune vérification n'est faite
314           On impose juste que valeur soit une string
315       """
316       if type(valeur) != types.StringType:
317         return 0
318       else:
319         return 1
320
321    def is_object_from(self,objet,classe):
322       """ 
323            Retourne 1 si valeur est un objet de la classe classe ou d'une sous-classe de classe,
324            0 sinon 
325       """
326       if type(objet) != types.InstanceType :
327         if type(objet) == types.StringType:
328           if not self.jdc :return 0
329           try :
330             objet = eval(objet,self.jdc.g_context)
331             if type(objet) != types.InstanceType : return 0
332           except:
333             return 0
334         else:
335           return 0
336       if not objet.__class__ == classe and not issubclass(objet.__class__,classe):
337         return 0
338       else:
339         return 1
340
341    def compare_type(self,valeur,type_permis):
342       """
343           Fonction booléenne qui retourne 1 si valeur est du type type_permis, 0 sinon
344       """
345       if type(valeur) == types.InstanceType and valeur.__class__.__name__ == 'PARAMETRE':
346         if type(valeur.valeur) == types.TupleType :
347           # on a à faire à un PARAMETRE qui définit une liste d'items
348           # --> on teste sur la première car on n'accepte que les liste homogènes
349           valeur = valeur.valeur[0]
350       if type_permis == 'R':
351         return self.is_reel(valeur)
352       elif type_permis == 'I':
353         return self.is_entier(valeur)
354       elif type_permis == 'C':
355         return self.is_complexe(valeur)
356       elif type_permis == 'shell':
357         return self.is_shell(valeur)
358       elif type_permis == 'TXM':
359         if type(valeur) != types.InstanceType:
360           return type(valeur)==types.StringType
361         else:
362           #XXX je n'y touche pas pour ne pas tout casser mais il serait
363           #XXX préférable d'appeler une méthode de valeur : return valeur.is_type('TXM'), par exemple
364           if valeur.__class__.__name__ == 'chaine' :
365             return 1
366           elif valeur.__class__.__name__ == 'PARAMETRE':
367             # il faut tester si la valeur du parametre est une string
368             return type(valeur.valeur)==types.StringType
369           else:
370             return 0
371       elif type(type_permis) == types.ClassType:
372         # on ne teste pas certains objets de type GEOM , assd, ...
373         # On appelle la méthode de classe is_object de type_permis.
374         # Comme valeur peut etre de n'importe quel type on utilise la fonction (is_object.im_func)
375         # et non pas la methode (is_object) ce qui risquerait de provoquer des erreurs
376         if type_permis.is_object.im_func(valeur):
377           return 1
378         else :
379           return self.is_object_from(valeur,type_permis)
380       else:
381         print "Type non encore géré %s" %`type_permis`
382         print self.nom,self.parent.nom,self.jdc.fichier
383
384    def isinintervalle(self,valeur,cr='non'):
385       """
386       Booléenne qui retourne 1 si la valeur passée en argument est comprise dans
387       le domaine de définition donné dans le catalogue, 0 sinon.
388       """
389       if type(valeur) not in (types.IntType,types.FloatType,types.LongType) :
390         return 1
391       else :
392         min = self.definition.val_min
393         max = self.definition.val_max
394         if min == '**': min = valeur -1
395         if max == '**': max = valeur +1
396         if valeur < min or valeur > max :
397           if cr=='oui':
398             self.cr.fatal(string.join(("La valeur :",`valeur`," du mot-clé ",self.nom,\
399                                        " est en dehors du domaine de validité [",`min`,",",`max`,"]")))
400           return 0
401         else :
402           return 1
403
404    def init_modif_up(self):
405       """
406          Propage l'état modifié au parent s'il existe et n'est l'objet 
407          lui-meme
408       """
409       if self.parent and self.parent != self :
410         self.parent.state = 'modified'
411
412    def report(self):
413       """ génère le rapport de validation de self """
414       self.cr=self.CR()
415       self.cr.debut = "Mot-clé simple : "+self.nom
416       self.cr.fin = "Fin Mot-clé simple : "+self.nom
417       self.state = 'modified'
418       try:
419         self.isvalid(cr='oui')
420       except AsException,e:
421         if CONTEXT.debug : traceback.print_exc()
422         self.cr.fatal(string.join(("Mot-clé simple : ",self.nom,str(e))))
423       return self.cr
424
425
426
427
428
429