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