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