Salome HOME
CCAR: Correction du pb AO2001-474, SD non nommée : impossible de la renommer ensuite
[tools/eficas.git] / Noyau / N_ETAPE.py
1 #@ MODIF N_ETAPE Noyau  DATE 26/06/2002   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 ETAPE qui sert à vérifier et à exécuter
23     une commande
24 """
25
26 # Modules Python
27 import types,sys,string,os
28 import linecache
29 import traceback
30
31 # Modules EFICAS
32 import N_MCCOMPO
33 from N_Exception import AsException
34 import N_utils
35 from N_utils import AsType
36
37 class ETAPE(N_MCCOMPO.MCCOMPO):
38    """
39       Cette classe hérite de MCCOMPO car ETAPE est un OBJECT composite
40
41    """
42    nature = "OPERATEUR"
43
44    # L'attribut de classe codex est utilisé pour rattacher le module de calcul éventuel (voir Build)
45    # On le met à None pour indiquer qu'il n'y a pas de module de calcul rattaché
46    codex=None
47
48    def __init__(self,oper=None,reuse=None,args={}):
49       """
50          Attributs :
51
52           - definition : objet portant les attributs de définition d'une étape de type opérateur. Il
53                          est initialisé par l'argument oper.
54
55           - reuse : indique le concept d'entrée réutilisé. Il se trouvera donc en sortie
56                     si les conditions d'exécution de l'opérateur l'autorise
57
58           - valeur : arguments d'entrée de type mot-clé=valeur. Initialisé avec l'argument args.
59
60       """
61       self.definition=oper
62       self.reuse=reuse
63       self.valeur=args
64       self.nettoiargs()
65       self.parent=CONTEXT.get_current_step()
66       self.etape = self
67       self.nom=oper.nom
68       self.idracine=oper.label
69       self.appel=N_utils.callee_where()
70       self.mc_globaux={}
71       self.sd=None
72       self.actif=1
73       self.make_register()
74
75    def make_register(self):
76       """
77          Initialise les attributs jdc, id, niveau et réalise les 
78          enregistrements nécessaires
79       """
80       if self.parent :
81          self.jdc = self.parent.get_jdc_root()
82          self.id=self.parent.register(self)
83          self.niveau=None
84       else:
85          self.jdc = self.parent =None
86          self.id=None
87          self.niveau=None
88
89    def nettoiargs(self):
90       """
91          Cette methode a pour fonction de retirer tous les arguments egaux à None
92          de la liste des arguments. Ils sont supposés non présents et donc retirés.
93       """
94       for k in self.valeur.keys():
95          if self.valeur[k] == None:del self.valeur[k]
96
97    def McBuild(self):
98       """
99          Demande la construction des sous-objets et les stocke dans l'attribut
100          mc_liste.
101       """
102       self.mc_liste=self.build_mc()
103
104    def Build_sd(self,nom):
105       """
106          Construit le concept produit de l'opérateur. Deux cas 
107          peuvent se présenter :
108         
109          - le parent n'est pas défini. Dans ce cas, l'étape prend en charge la création 
110            et le nommage du concept.
111
112          - le parent est défini. Dans ce cas, l'étape demande au parent la création et 
113            le nommage du concept.
114
115       """
116       if not self.isactif():return
117       self.sdnom=nom
118       try:
119          if self.parent:
120             sd= self.parent.create_sdprod(self,nom)
121             if type(self.definition.op_init) == types.FunctionType: 
122                apply(self.definition.op_init,(self,self.parent.g_context))
123          else:
124             sd=self.get_sd_prod()
125             # On n'utilise pas self.definition.op_init car self.parent 
126             # n'existe pas
127             if sd != None and self.reuse == None:
128                # On ne nomme le concept que dans le cas de non reutilisation 
129                # d un concept
130                sd.nom=nom
131          if self.jdc and self.jdc.par_lot == "NON" :
132             self.Execute()
133          return sd
134       except AsException,e:
135          raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
136                               'fichier : ',self.appel[1],e)
137       except EOFError:
138          # XXX Normalement le contexte courant doit etre le parent.
139          # Il n'y a pas de raison de remettre le contexte au parent
140          #self.reset_current_step()
141          raise
142       except :
143          l=traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2])
144          raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
145                            'fichier : ',self.appel[1]+'\n',
146                             string.join(l))
147
148    def Execute(self):
149       """
150          Cette methode est prevue pour faire une execution dans le cas
151          ou par_lot == 'NON'
152          Par defaut, elle ne fait rien
153       """
154       return
155
156    def get_sd_prod(self):
157       """
158           Retourne le concept résultat de l'étape
159           Deux cas :
160                    cas 1 : sd_prod de oper n'est pas une fonction
161                            il s'agit d'une sous classe de ASSD
162                            on construit le sd à partir de cette classe
163                            et on le retourne
164                    cas 2 : il s'agit d'une fonction
165                            on l'évalue avec les mots-clés de l'étape (mc_liste)
166                            on construit le sd à partir de la classe obtenue
167                            et on le retourne
168       """
169       if type(self.definition.sd_prod) == types.FunctionType:
170         d=self.cree_dict_valeurs(self.mc_liste)
171         try:
172           sd_prod= apply(self.definition.sd_prod,(),d)
173         except EOFError:
174           raise
175         except:
176           if CONTEXT.debug: traceback.print_exc()
177           l=traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],
178                                        sys.exc_info()[2])
179           raise AsException("impossible d affecter un type au resultat",
180                              string.join(l[2:]))
181           #         sys.exc_info()[0],sys.exc_info()[1],)
182       else:
183         sd_prod=self.definition.sd_prod
184       # on teste maintenant si la SD est réutilisée ou s'il faut la créer
185       if self.reuse:
186         # Il est preferable de traiter cette erreur ultérieurement : ce n'est pas une erreur fatale
187         #if AsType(self.reuse) != sd_prod:
188         #  raise AsException("type de concept reutilise incompatible avec type produit")
189         self.sd=self.reuse
190       else:
191         self.sd= sd_prod(etape=self)
192         # Si reuse n'a pas ete donné, c'est une erreur. Ne pas corriger afin de la detecter ensuite
193         #if self.definition.reentrant == 'o':
194         #  self.reuse = self.sd
195       return self.sd
196
197    def get_type_produit(self):
198       """
199           Retourne le type du concept résultat de l'étape
200           Deux cas :
201            cas 1 : sd_prod de oper n'est pas une fonction
202                    il s'agit d'une sous classe de ASSD
203                    on retourne le nom de la classe
204            cas 2 : il s'agit d'une fonction
205                     on l'évalue avec les mots-clés de l'étape (mc_liste)
206                    et on retourne son résultat
207       """
208       if type(self.definition.sd_prod) == types.FunctionType:
209         d=self.cree_dict_valeurs(self.mc_liste)
210         try:
211           sd_prod= apply(self.definition.sd_prod,(),d)
212         except:
213           #traceback.print_exc()
214           return None
215       else:
216         sd_prod=self.definition.sd_prod
217       return sd_prod
218
219    def get_etape(self):
220       """
221          Retourne l'étape à laquelle appartient self
222          Un objet de la catégorie etape doit retourner self pour indiquer que
223          l'étape a été trouvée
224          XXX fait double emploi avec self.etape ????
225       """
226       return self
227
228    def supprime(self):
229       """
230          Méthode qui supprime toutes les références arrières afin que l'objet puisse
231          etre correctement détruit par le garbage collector
232       """
233       N_MCCOMPO.MCCOMPO.supprime(self)
234       self.jdc=None
235       self.appel=None
236       if self.sd : self.sd.supprime()
237
238    def isactif(self):
239       """ 
240          Indique si l'étape est active (1) ou inactive (0)
241       """
242       return self.actif
243
244    def set_current_step(self):
245       """
246           Methode utilisee pour que l etape self se declare etape
247           courante. Utilise par les macros
248       """
249       #print "set_current_step ",self.nom
250       #traceback.print_stack(limit=3,file=sys.stdout)
251       cs= CONTEXT.get_current_step()
252       if self.parent != cs :
253          raise "L'étape courante %s devrait etre le parent de self : %s" % (cs,self)
254       else :
255          CONTEXT.unset_current_step()
256          CONTEXT.set_current_step(self)
257
258    def reset_current_step(self):
259       """ 
260             Methode utilisee par l'etape self qui remet son etape parent comme 
261              etape courante 
262       """
263       #print "reset_current_step ",self.nom
264       #traceback.print_stack(limit=3,file=sys.stdout)
265       cs= CONTEXT.get_current_step()
266       if self != cs :
267          raise "L'étape courante %s devrait etre self : %s" % (cs,self)
268       else :
269          CONTEXT.unset_current_step()
270          CONTEXT.set_current_step(self.parent)
271
272    def issubstep(self,etape):
273       """ 
274           Cette methode retourne un entier indiquant si etape est une
275           sous etape de self ou non
276           1 = oui
277           0 = non
278           Une étape simple n'a pas de sous etape
279       """
280       return 0
281
282    def get_file(self,unite=None,fic_origine=''):
283       """ 
284          Retourne le nom du fichier associe a l unite logique unite (entier)
285          ainsi que le source contenu dans le fichier
286       """
287       if self.jdc : return self.jdc.get_file(unite=unite,fic_origine=fic_origine)
288       else :
289          file = None
290          if unite != None:
291             if os.path.exists("fort."+str(unite)):
292                file= "fort."+str(unite)
293          if file == None : 
294             raise AsException("Impossible de trouver le fichier correspondant a l unite %s" % unite)
295          if not os.path.exists(file): 
296             raise AsException("%s n'est pas un fichier existant" % unite)
297          fproc=open(file,'r')
298          text=string.replace(fproc.read(),'\r\n','\n')
299          fproc.close()
300          linecache.cache[file]=0,0,string.split(text,'\n'),file
301          return file,text
302
303    def accept(self,visitor):
304       """
305          Cette methode permet de parcourir l'arborescence des objets
306          en utilisant le pattern VISITEUR
307       """
308       visitor.visitETAPE(self)
309
310    def update_context(self,d):
311       """
312           Cette methode doit updater le contexte fournit par
313           l'appelant en argument (d) en fonction de sa definition
314       """
315       if type(self.definition.op_init) == types.FunctionType:
316         apply(self.definition.op_init,(self,d))
317       if self.sd:
318         d[self.sd.nom]=self.sd
319
320
321
322