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