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