]> SALOME platform Git repositories - tools/eficas.git/blob - Ihm/I_MACRO_ETAPE.py
Salome HOME
CCAR: modification pour ajouter les options a la ligne de commande (voir Editeur...
[tools/eficas.git] / Ihm / I_MACRO_ETAPE.py
1 # -*- coding: utf-8 -*-
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 """
23 # Modules Python
24 import sys
25 import traceback,types,string
26
27 # Modules Eficas
28 import I_ETAPE
29 from Noyau.N_ASSD import ASSD
30
31 # import rajoutés suite à l'ajout de Build_sd --> à résorber
32 import Noyau, Validation.V_MACRO_ETAPE
33 from Noyau import N_Exception
34 from Noyau.N_Exception import AsException
35 # fin import à résorber
36
37 class MACRO_ETAPE(I_ETAPE.ETAPE):
38
39   def __init__(self):
40       self.typret=None
41       self.recorded_units={}
42
43   def get_sdprods(self,nom_sd):
44     """ 
45          Fonction : retourne le concept produit par l etape de nom nom_sd
46          s il existe sinon None
47     """
48     if self.sd and self.sd.nom == nom_sd :return self.sd
49     for co in self.sdprods:
50       if co.nom == nom_sd:return co
51     if type(self.definition.op_init) == types.FunctionType:
52       d={}
53       apply(self.definition.op_init,(self,d))
54       return d.get(nom_sd,None)
55     return None
56
57   def get_contexte_jdc(self,fichier,text):
58     """ 
59          Interprète text comme un texte de jdc et retourne le 
60          contexte final
61          cad le dictionnaire des sd disponibles à la dernière étape
62          Si text n'est pas un texte de jdc valide, retourne None
63          ou leve une exception
64          --> utilisée par ops.POURSUITE et INCLUDE
65     """
66     #print "get_contexte_jdc"
67     try:
68        # on essaie de créer un objet JDC auxiliaire avec un contexte initial
69        context_ini = self.parent.get_contexte_avant(self)
70
71        # Indispensable avant de creer un nouveau JDC
72        CONTEXT.unset_current_step()
73        args=self.jdc.args
74        prefix_include=None
75        if hasattr(self,'prefix'):
76           prefix_include=self.prefix
77        # ATTENTION : le dictionnaire recorded_units sert à memoriser les unites des 
78        # fichiers inclus. Il est preferable de garder le meme dictionnaire pendant
79        # tout le traitement et de ne pas le reinitialiser brutalement (utiliser 
80        # clear plutot) si on ne veut pas perdre la memoire des unites.
81        # En principe si la memorisation est faite au bon moment il n'est pas necessaire
82        # de prendre cette precaution mais ce n'est pas vrai partout.
83        old_recorded_units=self.recorded_units.copy()
84        #print "get_contexte_jdc",id(self.recorded_units)
85        #self.recorded_units.clear()
86
87        j=self.JdC_aux( procedure=text, nom=fichier,
88                                 appli=self.jdc.appli,
89                                 cata=self.jdc.cata,
90                                 cata_ord_dico=self.jdc.cata_ordonne_dico,
91                                 context_ini = context_ini,
92                                 jdc_pere=self.jdc,etape_include=self,
93                                 prefix_include=prefix_include,
94                                 recorded_units=self.recorded_units,
95                                 old_recorded_units=old_recorded_units,**args)
96
97        j.analyse()
98        # On récupère les étapes internes (pour validation)
99        self.etapes=j.etapes
100     except:
101        traceback.print_exc()
102        # On force le contexte (etape courante) à self
103        CONTEXT.unset_current_step()
104        CONTEXT.set_current_step(self)
105        return None
106
107     if not j.cr.estvide():
108        # Erreurs dans l'INCLUDE. On garde la memoire du fichier 
109        # mais on n'insere pas les concepts
110        # On force le contexte (etape courante) à self
111        CONTEXT.unset_current_step()
112        CONTEXT.set_current_step(self)
113        raise Exception("Impossible de relire le fichier\n"+str(j.cr))
114
115     if not j.isvalid():
116        # L'INCLUDE n'est pas valide.
117        # on produit un rapport d'erreurs
118        # On force le contexte (etape courante) à self
119        cr=j.report()
120        CONTEXT.unset_current_step()
121        CONTEXT.set_current_step(self)
122        raise Exception("Le fichier include contient des erreurs\n"+str(cr))
123
124     # Si aucune erreur rencontrée
125     # On recupere le contexte de l'include verifie
126     try:
127        j_context=j.get_verif_contexte()
128     except:
129        CONTEXT.unset_current_step()
130        CONTEXT.set_current_step(self)
131        raise
132
133     # On remplit le dictionnaire des concepts produits inclus
134     # en retirant les concepts présents dans le  contexte initial
135     # On ajoute egalement le concept produit dans le sds_dict du parent
136     # sans verification car on est sur (verification integrée) que 
137     # le nommage est possible
138     self.g_context.clear()
139     for k,v in j_context.items():
140        if not context_ini.has_key(k) or context_ini[k] != v:
141            self.g_context[k]=v
142            self.parent.sds_dict[k]=v
143
144
145     # On recupere le contexte courant
146     self.current_context=j.current_context
147     self.index_etape_courante=j.index_etape_courante
148     self.jdc_aux=j
149
150     # XXX j.supprime() ???
151     # On rétablit le contexte (etape courante) à self
152     CONTEXT.unset_current_step()
153     CONTEXT.set_current_step(self)
154
155     return j_context
156
157   def reevalue_sd_jdc(self):
158      """
159          Avec la liste des SD qui ont été supprimées, propage la 
160          disparition de ces SD dans toutes les étapes et descendants
161      """
162      l_sd_supp,l_sd_repl = self.diff_contextes()
163      for sd in l_sd_supp:
164         self.parent.delete_concept_after_etape(self,sd)
165      for old_sd,sd in l_sd_repl:
166         self.parent.replace_concept_after_etape(self,old_sd,sd)
167
168   def diff_contextes(self):
169      """ 
170          Réalise la différence entre les 2 contextes 
171          old_contexte_fichier_init et contexte_fichier_init
172          cad retourne la liste des sd qui ont disparu ou ne derivent pas 
173          de la meme classe et des sd qui ont ete remplacees
174      """
175      if not hasattr(self,'old_contexte_fichier_init'):return [],[]
176      l_sd_suppressed = []
177      l_sd_replaced = []
178      for old_key in self.old_contexte_fichier_init.keys():
179        if not self.contexte_fichier_init.has_key(old_key):
180          if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
181            l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
182        else:
183          if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
184             # Un concept de meme nom existe
185             old_class=self.old_contexte_fichier_init[old_key].__class__
186             if not isinstance(self.contexte_fichier_init[old_key],old_class):
187                # S'il n'est pas d'une classe derivee, on le supprime
188                l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
189             else:
190                l_sd_replaced.append((self.old_contexte_fichier_init[old_key],self.contexte_fichier_init[old_key]))
191      return l_sd_suppressed,l_sd_replaced
192       
193   def control_sdprods(self,d):
194       """
195           Cette methode doit updater le contexte fournit par
196           l'appelant en argument (d) en fonction de sa definition
197           tout en verifiant que ses concepts produits ne sont pas
198           deja definis dans le contexte
199       """
200       if hasattr(self,"fichier_unite"):
201          self.update_fichier_init(self.fichier_unite)
202          self.init_modif()
203
204       if type(self.definition.op_init) == types.FunctionType:
205         apply(self.definition.op_init,(self,d))
206       if self.sd:
207         if d.has_key(self.sd.nom):
208            # Le concept est deja defini
209            if self.reuse and self.reuse is d[self.sd.nom]:
210               # Le concept est reutilise : situation normale
211               pass
212            else:
213               # Redefinition du concept, on l'annule
214               #XXX on pourrait simplement annuler son nom pour conserver les objets
215               # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
216               self.sd=self.reuse=self.sdnom=None
217               self.init_modif()
218         else:
219            # Le concept n'est pas defini, on peut updater d
220            d[self.sd.nom]=self.sd
221       # On verifie les concepts a droite du signe =
222       for co in self.sdprods:
223         if d.has_key(co.nom) and co is not d[co.nom] :
224            self.delete_concept(co)
225         else:
226            d[co.nom]=co
227        
228
229   def supprime_sdprods(self):
230       """
231           Fonction:
232           Lors d'une destruction d'etape, detruit tous les concepts produits
233           Un opérateur n a qu un concept produit
234           Une procedure n'en a aucun
235           Une macro en a en général plus d'un
236       """
237       if not self.is_reentrant() :
238          # l'étape n'est pas réentrante
239          # le concept retourné par l'étape est à supprimer car il était
240          # créé par l'étape
241          if self.sd != None :
242             self.parent.del_sdprod(self.sd)
243             self.parent.delete_concept(self.sd)
244       # On détruit les concepts à droite du signe =
245       for co in self.sdprods:
246          self.parent.del_sdprod(co)
247          self.parent.delete_concept(co)
248       # Si la macro a des etapes et des concepts inclus, on les detruit
249       for nom_sd,co in self.g_context.items():
250          if not isinstance(co,ASSD):continue
251          self.parent.del_sdprod(co)
252          self.parent.delete_concept(co)
253       # On met g_context à blanc
254       self.g_context={}
255          
256   def make_contexte_include(self,fichier,text):
257     """
258         Cette méthode sert à créer un contexte en interprétant un texte source
259         Python
260     """
261     #print "make_contexte_include"
262     # on récupère le contexte d'un nouveau jdc dans lequel on interprete text
263     contexte = self.get_contexte_jdc(fichier,text)
264     if contexte == None :
265       raise Exception("Impossible de construire le jeu de commandes correspondant au fichier")
266     else:
267       # Pour les macros de type include : INCLUDE, INCLUDE_MATERIAU et POURSUITE
268       # l'attribut g_context est un dictionnaire qui contient les concepts produits par inclusion
269       # l'attribut contexte_fichier_init est un dictionnaire qui contient les concepts produits
270       # en sortie de macro. g_context est obtenu en retirant de contexte_fichier_init les concepts
271       # existants en debut de macro contenus dans context_ini (dans get_contexte_jdc)
272       # g_context est utilisé pour avoir les concepts produits par la macro
273       # contexte_fichier_init est utilisé pour avoir les concepts supprimés par la macro
274       self.contexte_fichier_init = contexte
275
276   def reevalue_fichier_init(self):
277       """Recalcule les concepts produits par le fichier enregistre"""
278       old_context=self.contexte_fichier_init
279       try:
280          self.make_contexte_include(self.fichier_ini ,self.fichier_text)
281       except:
282          l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
283          self.fichier_err = string.join(l)
284          #self.etapes=[]
285          self.g_context={}
286
287          self.old_contexte_fichier_init=old_context
288          self.contexte_fichier_init={}
289          self.reevalue_sd_jdc()
290          return
291
292       # L'evaluation s'est bien passee
293       self.fichier_err = None
294       self.old_contexte_fichier_init=old_context
295       self.reevalue_sd_jdc()
296
297   def update_fichier_init(self,unite):
298       """Reevalue le fichier init sans demander (dans la mesure du possible) a l'utilisateur 
299          les noms des fichiers
300          Ceci suppose que les relations entre unites et noms ont été memorisees préalablement
301       """
302       #print "update_fichier_init",unite
303       self.fichier_err=None
304       self.old_contexte_fichier_init=self.contexte_fichier_init
305
306       #print self,self.parent,self.parent.recorded_units
307       #if unite != self.fichier_unite or not self.parent.recorded_units.has_key(unite):
308       if not self.parent.recorded_units.has_key(unite):
309          # Changement d'unite ou Nouvelle unite
310          f,text=self.get_file(unite=unite,fic_origine=self.parent.nom)
311          units={}
312          if f is not None:
313             self.fichier_ini = f
314             self.fichier_text=text
315          self.recorded_units=units
316          if self.fichier_ini is None and self.jdc.appli:
317             self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
318                      message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
319       else:
320          # Meme unite existante
321          f,text,units=self.parent.recorded_units[unite]
322          self.fichier_ini = f
323          self.fichier_text=text
324          self.recorded_units=units
325
326       if self.fichier_ini is None:
327          # Le fichier n'est pas défini
328          self.fichier_err="Le fichier associé n'est pas défini"
329          self.parent.change_unit(unite,self,self.fichier_unite)
330          self.g_context={}
331          self.contexte_fichier_init={}
332          self.parent.reset_context()
333          self.reevalue_sd_jdc()
334          return
335
336       try:
337         self.make_contexte_include(self.fichier_ini,self.fichier_text)
338         # Les 3 attributs fichier_ini fichier_text recorded_units doivent etre corrects
339         # avant d'appeler change_unit
340         self.parent.change_unit(unite,self,self.fichier_unite)
341       except:
342         # Erreurs lors de l'evaluation de text dans un JDC auxiliaire
343         l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
344         # On conserve la memoire du nouveau fichier
345         # mais on n'utilise pas les concepts crees par ce fichier
346         # on met l'etape en erreur : fichier_err=string.join(l)
347         self.fichier_err=string.join(l)
348         self.parent.change_unit(unite,self,self.fichier_unite)
349         self.g_context={}
350         self.contexte_fichier_init={}
351
352       # Le contexte du parent doit etre reinitialise car les concepts 
353       # produits ont changé
354       self.parent.reset_context()
355       # Si des concepts ont disparu lors du changement de fichier, on 
356       # demande leur suppression
357       self.reevalue_sd_jdc()
358
359   def record_unite(self):
360       if self.nom == "POURSUITE":
361          self.parent.record_unit(None,self)
362       else:
363          if hasattr(self,'fichier_unite') : 
364             self.parent.record_unit(self.fichier_unite,self)
365
366   def get_file_memo(self,unite=None,fic_origine=''):
367       """Retourne le nom du fichier et le source correspondant a l'unite unite
368          Initialise en plus recorded_units
369       """
370       #print "get_file_memo",unite,fic_origine,self,self.parent
371       #print self.parent.old_recorded_units
372       #print self.parent.recorded_units
373       if unite is None:
374          units={}
375       else:
376          units=self.parent.recorded_units
377       if self.parent.old_recorded_units.has_key(unite):
378          f,text,units=self.parent.old_recorded_units[unite]
379          #print id(self.recorded_units)
380          self.recorded_units=units
381          #print id(self.recorded_units)
382          return f,text
383       elif self.jdc :
384          f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
385       else:
386          f,text=None,None
387       self.recorded_units=units
388       if f is None and self.jdc.appli:
389          self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
390                           message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
391       return f,text
392
393 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
394   def get_file(self,unite=None,fic_origine=''):
395       """Retourne le nom du fichier et le source correspondant a l'unite unite
396          Initialise en plus recorded_units
397       """
398       #print "get_file",unite
399       units={}
400       if self.jdc :
401          f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
402       else:
403          f,text=None,None
404       self.recorded_units=units
405       return f,text
406
407 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
408   def make_include(self,unite=None):
409       """
410           Inclut un fichier dont l'unite logique est unite
411           Cette methode est appelee par la fonction sd_prod de la macro INCLUDE
412           Si l'INCLUDE est invalide, la methode doit produire une exception 
413           Sinon on retourne None. Les concepts produits par l'INCLUDE sont
414           pris en compte par le JDC parent lors du calcul du contexte (appel de ???)
415       """
416       #print "make_include",unite
417       # On supprime l'attribut unite qui bloque l'evaluation du source de l'INCLUDE
418       # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
419       del self.unite
420       # Si unite n'a pas de valeur, l'etape est forcement invalide. On peut retourner None
421       if not unite : return
422
423       if not hasattr(self,'fichier_ini') : 
424          # Si le fichier n'est pas defini on le demande
425          f,text=self.get_file_memo(unite=unite,fic_origine=self.parent.nom)
426          # On memorise le fichier retourne
427          self.fichier_ini  = f
428          self.fichier_text = text
429          self.contexte_fichier_init={}
430          self.fichier_unite=unite
431          self.fichier_err=None
432          import Extensions.jdc_include
433          self.JdC_aux=Extensions.jdc_include.JdC_include
434
435          if f is None:
436              self.fichier_err="Le fichier INCLUDE n est pas defini"
437              self.parent.record_unit(unite,self)
438              raise Exception(self.fichier_err)
439
440          try:
441            self.make_contexte_include(self.fichier_ini ,self.fichier_text)
442            self.parent.record_unit(unite,self)
443          except:
444            l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
445            if self.jdc.appli:
446               self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
447                                             message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
448                                            )
449            self.parent.record_unit(unite,self)
450            self.g_context={}
451            self.fichier_err = string.join(l)
452            self.contexte_fichier_init={}
453            raise
454
455       else:
456          # Si le fichier est deja defini on ne reevalue pas le fichier
457          # et on leve une exception si une erreur a été enregistrée
458          self.update_fichier_init(unite)
459          self.fichier_unite=unite
460          if self.fichier_err is not None: raise Exception(self.fichier_err)
461         
462
463 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
464   def make_contexte(self,fichier,text):
465     """
466         Cette méthode sert à créer un contexte pour INCLUDE_MATERIAU
467         en interprétant un texte source Python
468         Elle est appelee par la fonction sd_prd d'INCLUDE_MATERIAU
469     """
470     # On supprime l'attribut mat qui bloque l'evaluation du source de l'INCLUDE_MATERIAU
471     # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
472     if hasattr(self,'mat'):del self.mat
473     self.fichier_ini =fichier
474     self.fichier_unite =fichier
475     self.fichier_text=text
476     self.fichier_err=None 
477     self.contexte_fichier_init={}
478     # On specifie la classe a utiliser pour le JDC auxiliaire
479     import Extensions.jdc_include
480     self.JdC_aux=Extensions.jdc_include.JdC_include
481     try:
482        self.make_contexte_include(self.fichier_ini ,self.fichier_text)
483        self.parent.record_unit(self.fichier_unite,self)
484     except:
485        l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
486        self.fichier_err = string.join(l)
487        self.parent.record_unit(self.fichier_unite,self)
488        self.g_context={}
489        self.contexte_fichier_init={}
490        raise
491
492 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
493   def update_sdprod(self,cr='non'):
494      # Cette methode peut etre appelee dans EFICAS avec des mots cles de 
495      # la commande modifies. Ceci peut conduire a la construction ou
496      # a la reconstruction d'etapes dans le cas d'INCLUDE ou d'INCLUDE_MATERIAU
497      # Il faut donc positionner le current_step avant l'appel
498      if self.state == "undetermined":return 1
499      CONTEXT.unset_current_step()
500      CONTEXT.set_current_step(self)
501      valid=Validation.V_MACRO_ETAPE.MACRO_ETAPE.update_sdprod(self,cr=cr)
502      CONTEXT.unset_current_step()
503      return valid
504
505 #ATTENTION SURCHARGE: cette methode surcharge celle de Noyau a garder en synchro 
506   def Build_sd(self,nom):
507       """
508            Methode de Noyau surchargee pour poursuivre malgre tout
509            si une erreur se produit pendant la creation du concept produit
510       """
511       try:
512          sd=Noyau.N_MACRO_ETAPE.MACRO_ETAPE.Build_sd(self,nom)
513       except AsException,e:
514          # Une erreur s'est produite lors de la construction du concept
515          # Comme on est dans EFICAS, on essaie de poursuivre quand meme
516          # Si on poursuit, on a le choix entre deux possibilités :
517          # 1. on annule la sd associée à self
518          # 2. on la conserve mais il faut la retourner
519          # On choisit de l'annuler
520          # En plus il faut rendre coherents sdnom et sd.nom
521          self.sd=None
522          self.sdnom=None
523          self.state="unchanged"
524          self.valid=0
525
526       return self.sd
527
528 #ATTENTION SURCHARGE: cette methode surcharge celle de Noyau a garder en synchro 
529   def make_poursuite(self):
530       """ Cette methode est appelée par la fonction sd_prod de la macro POURSUITE
531       """
532       if not hasattr(self,'fichier_ini') :
533          # Si le fichier n'est pas defini on le demande
534          f,text=self.get_file_memo(fic_origine=self.parent.nom)
535          # On memorise le fichier retourne
536          self.fichier_ini = f
537          self.fichier_unite = None
538          self.fichier_text = text
539          self.fichier_err=None
540          import Extensions.jdc_include
541          self.JdC_aux=Extensions.jdc_include.JdC_poursuite
542          self.contexte_fichier_init={}
543
544          if f is None:
545              self.fichier_err="Le fichier POURSUITE n'est pas defini"
546              self.parent.record_unit(None,self)
547              raise Exception(self.fichier_err)
548
549          try:
550            self.make_contexte_include(self.fichier_ini,self.fichier_text)
551            self.parent.record_unit(None,self)
552          except:
553            l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
554            if self.jdc.appli:
555               self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier poursuite",
556                                             message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
557                                            )
558            self.parent.record_unit(None,self)
559            self.g_context={}
560            self.fichier_err = string.join(l)
561            self.contexte_fichier_init={}
562            raise
563
564       else:
565          # Si le fichier est deja defini on ne reevalue pas le fichier
566          # et on leve une exception si une erreur a été enregistrée
567          self.update_fichier_init(None)
568          if self.fichier_err is not None: raise Exception(self.fichier_err)
569