Salome HOME
*** empty log message ***
[tools/eficas.git] / Noyau / N_ETAPE.py
1 # -*- coding: utf-8 -*-
2 #@ MODIF N_ETAPE Noyau  DATE 16/03/2004   AUTEUR GNICOLAS G.NICOLAS 
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     Ce module contient la classe ETAPE qui sert à vérifier et à exécuter
24     une commande
25 """
26
27 # Modules Python
28 import types,sys,string,os
29 import linecache
30 import traceback
31 from copy import copy
32
33 # Modules EFICAS
34 import N_MCCOMPO
35 from N_Exception import AsException
36 import N_utils
37 from N_utils import AsType
38
39 class ETAPE(N_MCCOMPO.MCCOMPO):
40    """
41       Cette classe hérite de MCCOMPO car ETAPE est un OBJECT composite
42
43    """
44    nature = "OPERATEUR"
45
46    # L'attribut de classe codex est utilisé pour rattacher le module de calcul éventuel (voir Build)
47    # On le met à None pour indiquer qu'il n'y a pas de module de calcul rattaché
48    codex=None
49
50    def __init__(self,oper=None,reuse=None,args={}):
51       """
52          Attributs :
53
54           - definition : objet portant les attributs de définition d'une étape de type opérateur. Il
55                          est initialisé par l'argument oper.
56
57           - reuse : indique le concept d'entrée réutilisé. Il se trouvera donc en sortie
58                     si les conditions d'exécution de l'opérateur l'autorise
59
60           - valeur : arguments d'entrée de type mot-clé=valeur. Initialisé avec l'argument args.
61
62       """
63       self.definition=oper
64       self.reuse=reuse
65       self.valeur=args
66       self.nettoiargs()
67       self.parent=CONTEXT.get_current_step()
68       self.etape = self
69       self.nom=oper.nom
70       self.idracine=oper.label
71       self.appel=N_utils.callee_where()
72       self.mc_globaux={}
73       self.sd=None
74       self.actif=1
75       self.make_register()
76
77    def make_register(self):
78       """
79          Initialise les attributs jdc, id, niveau et réalise les 
80          enregistrements nécessaires
81       """
82       if self.parent :
83          self.jdc = self.parent.get_jdc_root()
84          self.id=self.parent.register(self)
85          self.niveau=None
86       else:
87          self.jdc = self.parent =None
88          self.id=None
89          self.niveau=None
90
91    def nettoiargs(self):
92       """
93          Cette methode a pour fonction de retirer tous les arguments egaux à None
94          de la liste des arguments. Ils sont supposés non présents et donc retirés.
95       """
96       for k in self.valeur.keys():
97          if self.valeur[k] == None:del self.valeur[k]
98
99    def McBuild(self):
100       """
101          Demande la construction des sous-objets et les stocke dans l'attribut
102          mc_liste.
103       """
104       self.mc_liste=self.build_mc()
105
106    def Build_sd(self,nom):
107       """
108          Construit le concept produit de l'opérateur. Deux cas 
109          peuvent se présenter :
110         
111          - le parent n'est pas défini. Dans ce cas, l'étape prend en charge la création 
112            et le nommage du concept.
113
114          - le parent est défini. Dans ce cas, l'étape demande au parent la création et 
115            le nommage du concept.
116
117       """
118       if not self.isactif():return
119       self.sdnom=nom
120       try:
121          if self.parent:
122             sd= self.parent.create_sdprod(self,nom)
123             if type(self.definition.op_init) == types.FunctionType: 
124                apply(self.definition.op_init,(self,self.parent.g_context))
125          else:
126             sd=self.get_sd_prod()
127             # On n'utilise pas self.definition.op_init car self.parent 
128             # n'existe pas
129             if sd != None and self.reuse == None:
130                # On ne nomme le concept que dans le cas de non reutilisation 
131                # d un concept
132                sd.nom=nom
133       except AsException,e:
134          raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
135                               'fichier : ',self.appel[1],e)
136       except EOFError:
137          raise
138       except :
139          l=traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2])
140          raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
141                            'fichier : ',self.appel[1]+'\n',
142                             string.join(l))
143
144       self.Execute()
145       return sd
146
147    def Execute(self):
148       """
149          Cette methode est un point d'entree prevu pour realiser une execution immediatement
150          apres avoir construit les mots cles et le concept produit.
151          Par defaut, elle ne fait rien. Elle doit etre surchargee dans une autre partie du programme.
152       """
153       return
154
155    def get_sd_prod(self):
156       """
157           Retourne le concept résultat de l'étape
158           Deux cas :
159                    cas 1 : sd_prod de oper n'est pas une fonction
160                            il s'agit d'une sous classe de ASSD
161                            on construit le sd à partir de cette classe
162                            et on le retourne
163                    cas 2 : il s'agit d'une fonction
164                            on l'évalue avec les mots-clés de l'étape (mc_liste)
165                            on construit le sd à partir de la classe obtenue
166                            et on le retourne
167       """
168       if type(self.definition.sd_prod) == types.FunctionType:
169         d=self.cree_dict_valeurs(self.mc_liste)
170         try:
171           sd_prod= apply(self.definition.sd_prod,(),d)
172         except EOFError:
173           raise
174         except:
175           if CONTEXT.debug: traceback.print_exc()
176           l=traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],
177                                        sys.exc_info()[2])
178           raise AsException("impossible d affecter un type au resultat",
179                              string.join(l[2:]))
180           #         sys.exc_info()[0],sys.exc_info()[1],)
181       else:
182         sd_prod=self.definition.sd_prod
183       # on teste maintenant si la SD est réutilisée ou s'il faut la créer
184       if self.definition.reentrant != 'n' and self.reuse:
185         # Le concept produit est specifie reutilise (reuse=xxx). C'est une erreur mais non fatale.
186         # Elle sera traitee ulterieurement.
187         self.sd=self.reuse
188       else:
189         self.sd= sd_prod(etape=self)
190         # Si l'operateur est obligatoirement reentrant et reuse n'a pas ete specifie, c'est une erreur. 
191         # On ne fait rien ici. L'erreur sera traiter par la suite.
192       return self.sd
193
194    def get_type_produit(self):
195       """
196           Retourne le type du concept résultat de l'étape
197           Deux cas :
198            cas 1 : sd_prod de oper n'est pas une fonction
199                    il s'agit d'une sous classe de ASSD
200                    on retourne le nom de la classe
201            cas 2 : il s'agit d'une fonction
202                     on l'évalue avec les mots-clés de l'étape (mc_liste)
203                    et on retourne son résultat
204       """
205       if type(self.definition.sd_prod) == types.FunctionType:
206         d=self.cree_dict_valeurs(self.mc_liste)
207         try:
208           sd_prod= apply(self.definition.sd_prod,(),d)
209         except:
210           #traceback.print_exc()
211           return None
212       else:
213         sd_prod=self.definition.sd_prod
214       return sd_prod
215
216    def get_etape(self):
217       """
218          Retourne l'étape à laquelle appartient self
219          Un objet de la catégorie etape doit retourner self pour indiquer que
220          l'étape a été trouvée
221          XXX fait double emploi avec self.etape ????
222       """
223       return self
224
225    def supprime(self):
226       """
227          Méthode qui supprime toutes les références arrières afin que l'objet puisse
228          etre correctement détruit par le garbage collector
229       """
230       N_MCCOMPO.MCCOMPO.supprime(self)
231       self.jdc=None
232       self.appel=None
233       if self.sd : self.sd.supprime()
234
235    def isactif(self):
236       """ 
237          Indique si l'étape est active (1) ou inactive (0)
238       """
239       return self.actif
240
241    def set_current_step(self):
242       """
243           Methode utilisee pour que l etape self se declare etape
244           courante. Utilise par les macros
245       """
246       #print "set_current_step ",self.nom
247       #traceback.print_stack(limit=3,file=sys.stdout)
248       cs= CONTEXT.get_current_step()
249       if self.parent != cs :
250          raise "L'étape courante %s devrait etre le parent de self : %s" % (cs,self)
251       else :
252          CONTEXT.unset_current_step()
253          CONTEXT.set_current_step(self)
254
255    def reset_current_step(self):
256       """ 
257             Methode utilisee par l'etape self qui remet son etape parent comme 
258              etape courante 
259       """
260       #print "reset_current_step ",self.nom
261       #traceback.print_stack(limit=3,file=sys.stdout)
262       cs= CONTEXT.get_current_step()
263       if self != cs :
264          raise "L'étape courante %s devrait etre self : %s" % (cs,self)
265       else :
266          CONTEXT.unset_current_step()
267          CONTEXT.set_current_step(self.parent)
268
269    def issubstep(self,etape):
270       """ 
271           Cette methode retourne un entier indiquant si etape est une
272           sous etape de self ou non
273           1 = oui
274           0 = non
275           Une étape simple n'a pas de sous etape
276       """
277       return 0
278
279    def get_file(self,unite=None,fic_origine=''):
280       """ 
281          Retourne le nom du fichier associe a l unite logique unite (entier)
282          ainsi que le source contenu dans le fichier
283       """
284       if self.jdc : return self.jdc.get_file(unite=unite,fic_origine=fic_origine)
285       else :
286          file = None
287          if unite != None:
288             if os.path.exists("fort."+str(unite)):
289                file= "fort."+str(unite)
290          if file == None : 
291             raise AsException("Impossible de trouver le fichier correspondant a l unite %s" % unite)
292          if not os.path.exists(file): 
293             raise AsException("%s n'est pas un fichier existant" % unite)
294          fproc=open(file,'r')
295          text=string.replace(fproc.read(),'\r\n','\n')
296          fproc.close()
297          linecache.cache[file]=0,0,string.split(text,'\n'),file
298          return file,text
299
300    def accept(self,visitor):
301       """
302          Cette methode permet de parcourir l'arborescence des objets
303          en utilisant le pattern VISITEUR
304       """
305       visitor.visitETAPE(self)
306
307    def update_context(self,d):
308       """
309           Cette methode doit updater le contexte fournit par
310           l'appelant en argument (d) en fonction de sa definition
311       """
312       if type(self.definition.op_init) == types.FunctionType:
313         apply(self.definition.op_init,(self,d))
314       if self.sd:
315         d[self.sd.nom]=self.sd
316
317    def copy(self):
318       """ Méthode qui retourne une copie de self non enregistrée auprès du JDC
319           et sans sd 
320       """
321       etape = copy(self)
322       etape.sd = None
323       etape.state = 'modified'
324       etape.reuse = None
325       etape.sdnom = None
326       etape.etape=etape
327       etape.mc_liste=[]
328       for objet in self.mc_liste:
329         new_obj = objet.copy()
330         new_obj.reparent(etape)
331         etape.mc_liste.append(new_obj)
332       return etape
333
334    def copy_reuse(self,old_etape):
335       """ Méthode qui copie le reuse d'une autre étape. 
336       """
337       if hasattr(old_etape,"reuse") :
338         self.reuse = old_etape.reuse
339
340    def copy_sdnom(self,old_etape):
341       """ Méthode qui copie le sdnom d'une autre étape. 
342       """
343       if hasattr(old_etape,"sdnom") :
344         self.sdnom = old_etape.sdnom
345
346    def get_sd_utilisees(self):
347       """ 
348           Retourne la liste des concepts qui sont utilisés à l'intérieur d'une commande
349           ( comme valorisation d'un MCS) 
350       """
351       l=[]
352       for child in self.mc_liste:
353         l.extend(child.get_sd_utilisees())
354       return l
355
356    def get_sd_mcs_utilisees(self):
357       """ 
358           Retourne la ou les SD utilisée par self sous forme d'un dictionnaire :
359           . Si aucune sd n'est utilisée, le dictionnaire est vide.
360           . Sinon, les clés du dictionnaire sont les mots-clés derrière lesquels on
361             trouve des sd ; la valeur est la liste des sd attenante.
362             Exemple : { 'VALE_F': [ <Cata.cata.para_sensi instance at 0x9419854>,
363                                     <Cata.cata.para_sensi instance at 0x941a204> ],
364                         'MODELE': [<Cata.cata.modele instance at 0x941550c>] }
365       """
366       dico = {}
367       for child in self.mc_liste:
368         daux = child.get_sd_mcs_utilisees()
369         for cle in daux.keys():
370           dico[cle] = daux[cle]
371       return dico
372
373    def reparent(self,parent):
374      """
375          Cette methode sert a reinitialiser la parente de l'objet
376      """
377      self.parent=parent
378      self.jdc=parent.get_jdc_root()
379      self.etape=self
380      for mocle in self.mc_liste:
381         mocle.reparent(self)
382
383    def get_cmd(self,nomcmd):
384       """
385           Méthode pour recuperer la definition d'une commande
386           donnee par son nom dans les catalogues declares
387           au niveau du jdc
388           Appele par un ops d'une macro en Python
389       """
390       return self.jdc.get_cmd(nomcmd)
391
392    def copy_intern(self,etape):
393       """
394           Méthode permettant lors du processus de recopie de copier
395           les elements internes d'une etape dans une autre
396       """
397       return
398
399    def full_copy(self,parent=None):
400        """
401           Méthode permettant d'effectuer une copie complète
402           d'une étape (y compris concept produit, éléments internes)
403           Si l'argument parent est fourni, la nouvelle étape
404           aura cet objet comme parent.
405        """
406        new_etape = self.copy()
407        new_etape.copy_reuse(self)
408        new_etape.copy_sdnom(self)
409        if parent: new_etape.reparent(parent)
410        if self.sd :
411           new_sd = self.sd.__class__(etape=new_etape)
412           new_etape.sd = new_sd
413           if self.reuse == None :
414              new_etape.parent.NommerSdprod(new_sd,self.sd.nom)
415           else :
416              new_sd.nom = self.sd.nom
417        new_etape.copy_intern(self)
418        return new_etape