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