]> SALOME platform Git repositories - tools/eficas.git/blob - Ihm/I_MACRO_ETAPE.py
Salome HOME
correction bug en relecture fichier contenant des INCLUDEs
[tools/eficas.git] / Ihm / I_MACRO_ETAPE.py
1 #            CONFIGURATION MANAGEMENT OF EDF VERSION
2 # ======================================================================
3 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
4 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
5 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
6 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
7 # (AT YOUR OPTION) ANY LATER VERSION.
8 #
9 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
10 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
11 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
12 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
13 #
14 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
15 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
16 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
17 #
18 #
19 # ======================================================================
20 """
21 """
22 # Modules Python
23 import sys
24 import traceback,types,string
25
26 # Modules Eficas
27 import I_ETAPE
28 from Noyau.N_ASSD import ASSD
29
30 # import rajoutés suite à l'ajout de Build_sd --> à résorber
31 import Noyau, Validation.V_MACRO_ETAPE
32 from Noyau import N_Exception
33 from Noyau.N_Exception import AsException
34 # fin import à résorber
35
36 class MACRO_ETAPE(I_ETAPE.ETAPE):
37
38   def __init__(self):
39       self.typret=None
40
41   def get_sdprods(self,nom_sd):
42     """ 
43          Fonction : retourne le concept produit par l etape de nom nom_sd
44                     s il existe sinon None
45     """
46     if self.sd and self.sd.nom == nom_sd :return self.sd
47     for co in self.sdprods:
48       if co.nom == nom_sd:return co
49     if type(self.definition.op_init) == types.FunctionType:
50       d={}
51       apply(self.definition.op_init,(self,d))
52       return d.get(nom_sd,None)
53     return None
54
55   def get_contexte_jdc(self,fichier,text):
56     """ 
57          Interprète text comme un texte de jdc et retourne le 
58          contexte final
59          cad le dictionnaire des sd disponibles à la dernière étape
60          Si text n'est pas un texte de jdc valide, retourne None
61          ou leve une exception
62          --> utilisée par ops.POURSUITE et INCLUDE
63     """
64     try:
65        # on essaie de créer un objet JDC auxiliaire avec un contexte initial
66        context_ini = self.parent.get_contexte_avant(self)
67
68        # Indispensable avant de creer un nouveau JDC
69        CONTEXT.unset_current_step()
70        args=self.jdc.args
71        prefix_include=None
72        if hasattr(self,'prefix'):
73           prefix_include=self.prefix
74
75        j=self.JdC_aux( procedure=text,cata=self.jdc.cata,
76                                 nom=fichier,
77                                 context_ini = context_ini,
78                                 appli=self.jdc.appli,
79                                 jdc_pere=self.jdc,etape_include=self,
80                                 prefix_include=prefix_include,**args)
81
82        j.analyse()
83     except:
84        traceback.print_exc()
85        # On force le contexte (etape courante) à self
86        CONTEXT.unset_current_step()
87        CONTEXT.set_current_step(self)
88        return None
89
90     if not j.cr.estvide():
91        # On force le contexte (etape courante) à self
92        CONTEXT.unset_current_step()
93        CONTEXT.set_current_step(self)
94        # Erreurs dans l'INCLUDE. On garde la memoire du fichier mais on n'insere pas les concepts
95        # et les etapes. Ce traitement doit etre fait par l'appelant qui recoit l'exception
96        raise Exception("Impossible de relire le fichier\n"+str(j.cr))
97
98     cr=j.report()
99     if not cr.estvide():
100        # On force le contexte (etape courante) à self
101        CONTEXT.unset_current_step()
102        CONTEXT.set_current_step(self)
103        raise Exception("Le fichier include contient des erreurs\n"+str(j.cr))
104
105     # Cette verification n'est plus necessaire elle est integree dans le JDC_INCLUDE
106     #self.verif_contexte(j_context)
107
108     # On recupere le contexte apres la derniere etape
109     j_context=j.get_contexte_avant(None)
110
111     # On remplit le dictionnaire des concepts produits inclus
112     # en retirant les concepts présents dans le  contexte initial
113     # On ajoute egalement le concept produit dans le sds_dict du parent
114     # sans verification car on est sur (verification integrée) que le nommage est possible
115     self.g_context.clear()
116     for k,v in j_context.items():
117        if not context_ini.has_key(k) or context_ini[k] != v:
118            self.g_context[k]=v
119            self.parent.sds_dict[k]=v
120
121     # On récupère les étapes internes (pour validation)
122     self.etapes=j.etapes
123
124     # ainsi que le contexte courant
125     self.current_context=j.current_context
126     self.index_etape_courante=j.index_etape_courante
127
128     # XXX j.supprime() ???
129     # On force le contexte (etape courante) à self
130     CONTEXT.unset_current_step()
131     CONTEXT.set_current_step(self)
132
133     return j_context
134
135   def verif_contexte(self,context):
136      """
137          On verifie que le contexte context peut etre inséré dans le jeu
138          de commandes à la position de self
139      """
140      for nom_sd,sd in context.items():
141         if not isinstance(sd,ASSD):continue
142         if self.parent.get_sd_apres_etape(nom_sd,etape=self):
143            # Il existe un concept apres self => impossible d'inserer
144            raise Exception("Impossible d'inclure le fichier. Un concept de nom " + 
145                            "%s existe déjà dans le jeu de commandes." % nom_sd)
146
147   def reevalue_sd_jdc(self):
148      """
149          Avec la liste des SD qui ont été supprimées, propage la 
150          disparition de ces SD dans toutes les étapes et descendants
151      """
152      l_sd_supp,l_sd_repl = self.diff_contextes()
153      for sd in l_sd_supp:
154         self.parent.delete_concept_after_etape(self,sd)
155      for old_sd,sd in l_sd_repl:
156         self.parent.replace_concept_after_etape(self,old_sd,sd)
157
158   def diff_contextes(self):
159      """ 
160          Réalise la différence entre les 2 contextes 
161          old_contexte_fichier_init et contexte_fichier_init
162          cad retourne la liste des sd qui ont disparu ou ne derivent pas de la meme classe
163          et des sd qui ont ete remplacees
164      """
165      if not hasattr(self,'old_contexte_fichier_init'):return [],[]
166      l_sd_suppressed = []
167      l_sd_replaced = []
168      for old_key in self.old_contexte_fichier_init.keys():
169        if not self.contexte_fichier_init.has_key(old_key):
170          if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
171            l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
172        else:
173          if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
174             # Un concept de meme nom existe
175             old_class=self.old_contexte_fichier_init[old_key].__class__
176             if not isinstance(self.contexte_fichier_init[old_key],old_class):
177                # S'il n'est pas d'une classe derivee, on le supprime
178                l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
179             else:
180                l_sd_replaced.append((self.old_contexte_fichier_init[old_key],self.contexte_fichier_init[old_key]))
181      return l_sd_suppressed,l_sd_replaced
182       
183   def control_sdprods(self,d):
184       """
185           Cette methode doit updater le contexte fournit par
186           l'appelant en argument (d) en fonction de sa definition
187           tout en verifiant que ses concepts produits ne sont pas
188           deja definis dans le contexte
189       """
190       if type(self.definition.op_init) == types.FunctionType:
191         apply(self.definition.op_init,(self,d))
192       if self.sd:
193         if d.has_key(self.sd.nom):
194            # Le concept est deja defini
195            if self.reuse and self.reuse is d[self.sd.nom]:
196               # Le concept est reutilise : situation normale
197               pass
198            else:
199               # Redefinition du concept, on l'annule
200               #XXX on pourrait simplement annuler son nom pour conserver les objets
201               # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
202               self.sd=self.reuse=self.sdnom=None
203               self.init_modif()
204         else:
205            # Le concept n'est pas defini, on peut updater d
206            d[self.sd.nom]=self.sd
207       # On verifie les concepts a droite du signe =
208       for co in self.sdprods:
209         if d.has_key(co.nom) and co is not d[co.nom] :
210            self.delete_concept(co)
211         else:
212            d[co.nom]=co
213        
214
215   def supprime_sdprods(self):
216       """
217           Fonction:
218             Lors d'une destruction d'etape, detruit tous les concepts produits
219             Un opérateur n a qu un concept produit
220             Une procedure n'en a aucun
221             Une macro en a en général plus d'un
222       """
223       if not self.is_reentrant() :
224          # l'étape n'est pas réentrante
225          # le concept retourné par l'étape est à supprimer car il était
226          # créé par l'étape
227          if self.sd != None :
228             self.parent.del_sdprod(self.sd)
229             self.parent.delete_concept(self.sd)
230       # On détruit les concepts à droite du signe =
231       for co in self.sdprods:
232          self.parent.del_sdprod(co)
233          self.parent.delete_concept(co)
234       # Si la macro a des etapes et des concepts inclus, on les detruit
235       for nom_sd,co in self.g_context.items():
236          if not isinstance(co,ASSD):continue
237          self.parent.del_sdprod(co)
238          self.parent.delete_concept(co)
239       # On met g_context à blanc
240       self.g_context={}
241          
242 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
243   def Build_sd(self,nom):
244      """
245         Construit le concept produit de l'opérateur. Deux cas 
246         peuvent se présenter :
247
248         - le parent n'est pas défini. Dans ce cas, l'étape prend en charge 
249           la création et le nommage du concept.
250
251         - le parent est défini. Dans ce cas, l'étape demande au parent la 
252           création et le nommage du concept.
253
254      """
255      if not self.isactif():return
256      # CCAR : meme modification que dans I_ETAPE
257      if not self.isvalid(sd='non') : return
258      self.sdnom=nom
259      try:
260         # On positionne la macro self en tant que current_step pour que les 
261         # étapes créées lors de l'appel à sd_prod et à op_init aient la macro
262         #  comme parent 
263         self.set_current_step()
264         if self.parent:
265            sd= self.parent.create_sdprod(self,nom)
266            if type(self.definition.op_init) == types.FunctionType: 
267               apply(self.definition.op_init,(self,self.parent.g_context))
268         else:
269            sd=self.get_sd_prod()
270            if sd != None and self.reuse == None:
271               # On ne nomme le concept que dans le cas de non reutilisation 
272               # d un concept
273               sd.nom=nom
274         self.reset_current_step()
275         if self.jdc and self.jdc.par_lot == "NON" :
276            self.Execute()
277         return sd
278      except AsException,e:
279         self.reset_current_step()
280         # Une erreur s'est produite lors de la construction du concept
281         # Comme on est dans EFICAS, on essaie de poursuivre quand meme
282         # Si on poursuit, on a le choix entre deux possibilités :
283         # 1. on annule la sd associée à self
284         # 2. on la conserve mais il faut qu'elle soit correcte et la retourner
285         # En plus il faut rendre coherents sdnom et sd.nom
286         # On choisit de retourner None et de mettre l'etape invalide 
287         self.sd=None
288         self.sdnom=None
289         self.state="unchanged"
290         self.valid=0
291         return self.sd
292         #raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
293         #                     'fichier : ',self.appel[1],e)
294      except EOFError:
295         raise
296      except :
297         self.reset_current_step()
298         l=traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2])
299         raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
300                           'fichier : ',self.appel[1]+'\n',
301                            string.join(l))
302
303   def make_contexte_include(self,fichier,text):
304     """
305         Cette méthode sert à créer un contexte en interprétant un texte source
306         Python
307     """
308     # on récupère le contexte d'un nouveau jdc dans lequel on interprete text
309     contexte = self.get_contexte_jdc(fichier,text)
310     if contexte == None :
311       raise Exception("Impossible de construire le jeu de commandes correspondant au fichier")
312     else:
313       # Pour les macros de type include : INCLUDE, INCLUDE_MATERIAU et POURSUITE
314       # l'attribut g_context est un dictionnaire qui contient les concepts produits par inclusion
315       # l'attribut contexte_fichier_init est un dictionnaire qui contient les concepts produits
316       # en sortie de macro. g_context est obtenu en retirant de contexte_fichier_init les concepts
317       # existants en debut de macro contenus dans context_ini (dans get_contexte_jdc)
318       # g_context est utilisé pour avoir les concepts produits par la macro
319       # contexte_fichier_init est utilisé pour avoir les concepts supprimés par la macro
320       self.contexte_fichier_init = contexte
321
322   def reevalue_fichier_init(self):
323       """Recalcule les concepts produits par le fichier enregistre"""
324       old_context=self.contexte_fichier_init
325       try:
326          self.make_contexte_include(self.fichier_ini ,self.fichier_text)
327       except:
328          l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
329          self.fichier_err = string.join(l)
330          self.etapes=[]
331          self.g_context={}
332
333          self.old_contexte_fichier_init=old_context
334          self.contexte_fichier_init={}
335          self.reevalue_sd_jdc()
336          return
337
338       # L'evaluation s'est bien passee
339       self.fichier_err = None
340       self.old_contexte_fichier_init=old_context
341       self.reevalue_sd_jdc()
342
343   def make_poursuite(self):
344       """ Cette methode est appelée par la fonction sd_prod de la macro POURSUITE
345       """
346       if not hasattr(self,'fichier_ini') :
347          # Si le fichier n'est pas defini on le demande
348          f,text=self.get_file(fic_origine=self.parent.nom)
349          # On memorise le fichier retourne
350          self.fichier_ini = f
351          self.fichier_text = text
352          import Extensions.jdc_include
353          self.JdC_aux=Extensions.jdc_include.JdC_poursuite
354          self.contexte_fichier_init={}
355          if f is None:
356              self.fichier_err="Le fichier POURSUITE n'est pas defini"
357          else:
358              self.fichier_err=None
359
360          if self.fichier_err is not None: raise Exception(self.fichier_err)
361
362          try:
363            self.make_contexte_include(self.fichier_ini,self.fichier_text)
364          except:
365            l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
366            if self.jdc.appli:
367               self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier poursuite",
368                                             message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
369                                            )
370            self.g_context={}
371            self.etapes=[]
372            self.fichier_err = string.join(l)
373            self.contexte_fichier_init={}
374            raise
375
376       else:
377          # Si le fichier est deja defini on ne reevalue pas le fichier
378          # et on leve une exception si une erreur a été enregistrée
379          if self.fichier_err is not None: raise Exception(self.fichier_err)
380
381
382 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
383   def make_include(self,unite=None):
384       """
385           Inclut un fichier dont l'unite logique est unite
386           Cette methode est appelee par la fonction sd_prod de la macro INCLUDE
387           Si l'INCLUDE est invalide, la methode doit produire une exception 
388           Sinon on retourne None. Les concepts produits par l'INCLUDE sont
389           pris en compte par le JDC parent lors du calcul du contexte (appel de ???)
390       """
391
392       # On supprime l'attribut unite qui bloque l'evaluation du source de l'INCLUDE
393       # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
394       del self.unite
395       # Si unite n'a pas de valeur, l'etape est forcement invalide. On peut retourner None
396       if not unite : return
397
398       if not hasattr(self,'fichier_ini') : 
399          # Si le fichier n'est pas defini on le demande
400          f,text=self.get_file(unite=unite,fic_origine=self.parent.nom)
401          # On memorise le fichier retourne
402          self.fichier_ini  = f
403          self.fichier_text = text
404          self.contexte_fichier_init={}
405          if f is None:
406              self.fichier_err="Le fichier INCLUDE n est pas defini"
407          else:
408              self.fichier_err=None
409          import Extensions.jdc_include
410          self.JdC_aux=Extensions.jdc_include.JdC_include
411
412          if self.fichier_err is not None: raise Exception(self.fichier_err)
413
414          try:
415            self.make_contexte_include(self.fichier_ini ,self.fichier_text)
416          except:
417            l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
418            if self.jdc.appli:
419               self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
420                                             message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
421                                            )
422            self.g_context={}
423            self.etapes=[]
424            self.fichier_err = string.join(l)
425            self.contexte_fichier_init={}
426            raise
427
428       else:
429          # Si le fichier est deja defini on ne reevalue pas le fichier
430          # et on leve une exception si une erreur a été enregistrée
431          #self.reevalue_fichier_init()
432          if self.fichier_err is not None: raise Exception(self.fichier_err)
433         
434
435 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
436   def make_contexte(self,fichier,text):
437     """
438         Cette méthode sert à créer un contexte pour INCLUDE_MATERIAU
439         en interprétant un texte source Python
440         Elle est appelee par la fonction sd_prd d'INCLUDE_MATERIAU
441     """
442     # On supprime l'attribut mat qui bloque l'evaluation du source de l'INCLUDE_MATERIAU
443     # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
444     if hasattr(self,'mat'):del self.mat
445     self.fichier_ini =fichier
446     self.fichier_text=text
447     self.fichier_err=None 
448     self.contexte_fichier_init={}
449     # On specifie la classe a utiliser pour le JDC auxiliaire
450     import Extensions.jdc_include
451     self.JdC_aux=Extensions.jdc_include.JdC_include
452     try:
453        self.make_contexte_include(self.fichier_ini ,self.fichier_text)
454     except:
455        l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
456        self.g_context={}
457        self.etapes=[]
458        self.fichier_err = string.join(l)
459        self.contexte_fichier_init={}
460        raise
461
462 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
463   def update_sdprod(self,cr='non'):
464      # Cette methode peut etre appelee dans EFICAS avec des mots cles de 
465      # la commande modifies. Ceci peut conduire a la construction ou
466      # a la reconstruction d'etapes dans le cas d'INCLUDE ou d'INCLUDE_MATERIAU
467      # Il faut donc positionner le current_step avant l'appel
468      CONTEXT.unset_current_step()
469      CONTEXT.set_current_step(self)
470      valid=Validation.V_MACRO_ETAPE.MACRO_ETAPE.update_sdprod(self,cr=cr)
471      CONTEXT.unset_current_step()
472      return valid
473