Salome HOME
CCAR: merge de la version de developpement V1_12a2 dans la branche principale
[tools/eficas.git] / Noyau / N_MACRO_ETAPE.py
1 #@ MODIF N_MACRO_ETAPE Noyau  DATE 16/05/2007   AUTEUR COURTOIS 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 MACRO_ETAPE qui sert à vérifier et à exécuter
26     une commande
27 """
28
29 # Modules Python
30 import types,sys,string
31 import traceback
32
33 # Modules EFICAS
34 import N_MCCOMPO
35 import N_ETAPE
36 from N_Exception import AsException
37 import N_utils
38 from N_utils import AsType
39 from N_CO import CO
40 from N_ASSD import ASSD
41
42 class MACRO_ETAPE(N_ETAPE.ETAPE):
43    """
44
45    """
46    nature = "COMMANDE"
47    typeCO=CO
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 
53               de type macro-commande. Il est initialisé par 
54               l'argument oper.
55
56             - reuse : indique le concept d'entrée réutilisé. Il se trouvera donc
57               en sortie si les conditions d'exécution de l'opérateur 
58               l'autorise
59
60             - valeur : arguments d'entrée de type mot-clé=valeur. Initialisé 
61               avec l'argument args.
62
63       """
64       self.definition=oper
65       self.reuse=reuse
66       self.valeur=args
67       self.nettoiargs()
68       self.parent=CONTEXT.get_current_step()
69       self.etape = self
70       self.nom=oper.nom
71       self.idracine=oper.label
72       self.appel=N_utils.callee_where()
73       self.mc_globaux={}
74       self.g_context={}
75       # Contexte courant
76       self.current_context={}
77       self.index_etape_courante=0
78       self.etapes=[]
79       self.sds=[]
80       #  Dans le cas d'une macro écrite en Python, l'attribut Outputs est un 
81       #  dictionnaire qui contient les concepts produits de sortie 
82       #  (nom : ASSD) déclarés dans la fonction sd_prod
83       self.Outputs={}
84       self.sd=None
85       self.actif=1
86       self.sdprods=[]
87       self.make_register()
88       self.UserError="UserError"
89
90    def make_register(self):
91       """
92          Initialise les attributs jdc, id, niveau et réalise les enregistrements
93          nécessaires
94       """
95       if self.parent :
96          self.jdc = self.parent.get_jdc_root()
97          self.id=self.parent.register(self)
98          self.niveau=None
99          self.UserError=self.jdc.UserError
100       else:
101          self.jdc = self.parent =None
102          self.id=None
103          self.niveau=None
104          self.UserError="UserError"
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 
112              la création et le nommage du concept.
113
114            - le parent est défini. Dans ce cas, l'étape demande au parent la 
115              création et le nommage du concept.
116
117       """
118       self.sdnom=nom
119       try:
120          # On positionne la macro self en tant que current_step pour que les 
121          # étapes créées lors de l'appel à sd_prod et à op_init aient la macro
122          #  comme parent 
123          self.set_current_step()
124          if self.parent:
125             sd= self.parent.create_sdprod(self,nom)
126             if type(self.definition.op_init) == types.FunctionType: 
127                apply(self.definition.op_init,(self,self.parent.g_context))
128          else:
129             sd=self.get_sd_prod()
130             if sd != None and self.reuse == None:
131                # On ne nomme le concept que dans le cas de non reutilisation 
132                # d un concept
133                sd.set_name(nom)
134          self.reset_current_step()
135       except AsException,e:
136          self.reset_current_step()
137          raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
138                               'fichier : ',self.appel[1],e)
139       except (EOFError,self.UserError):
140          # Le retablissement du step courant n'est pas strictement necessaire. On le fait pour des raisons de coherence
141          self.reset_current_step()
142          raise
143       except :
144          self.reset_current_step()
145          l=traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2])
146          raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
147                            'fichier : ',self.appel[1]+'\n',
148                             string.join(l))
149
150       self.Execute()
151       return sd
152
153    def mark_CO(self):
154       """
155          Marquage des concepts CO d'une macro-commande
156       """
157       # On marque les concepts CO pour verification ulterieure de leur bonne utilisation
158       l=self.get_all_co()
159       for c in l:
160           #if not hasattr(c,"_etape") or c._etape is not c.etape: 
161              c._etape=self
162       return l
163
164    def get_sd_prod(self):
165       """
166         Retourne le concept résultat d'une macro étape
167         La difference avec une etape ou une proc-etape tient a ce que
168         le concept produit peut exister ou pas
169
170         Si sd_prod == None le concept produit n existe pas on retourne None
171
172         Deux cas :
173          - cas 1 : sd_prod  n'est pas une fonction
174                  il s'agit d'une sous classe de ASSD
175                  on construit le sd à partir de cette classe
176                  et on le retourne
177          - cas 2 : sd_prod est une fonction
178                  on l'évalue avec les mots-clés de l'étape (mc_liste)
179                  on construit le sd à partir de la classe obtenue
180                  et on le retourne
181       """
182       sd_prod=self.definition.sd_prod
183       self.typret=None
184       # On marque les concepts CO pour verification ulterieure de leur bonne utilisation
185       self.mark_CO()
186
187       if type(self.definition.sd_prod) == types.FunctionType:
188         d=self.cree_dict_valeurs(self.mc_liste)
189         try:
190           # la sd_prod d'une macro a l'objet macro_etape lui meme en premier argument
191           # Comme sd_prod peut invoquer la méthode type_sdprod qui ajoute
192           # les concepts produits dans self.sdprods, il faut le mettre à zéro avant de l'appeler
193           self.sdprods=[]
194           sd_prod= apply(sd_prod,(self,),d)
195         except (EOFError,self.UserError):
196           raise
197         except:
198           if CONTEXT.debug: traceback.print_exc()
199           l=traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2])
200           raise AsException("impossible d affecter un type au resultat\n",string.join(l[2:]))
201
202       # on teste maintenant si la SD est réutilisée ou s'il faut la créer
203       if self.definition.reentrant != 'n' and self.reuse:
204         # Le concept produit est specifie reutilise (reuse=xxx). C'est une erreur mais non fatale.
205         # Elle sera traitee ulterieurement.
206         self.sd=self.reuse
207       else:
208         if sd_prod == None:
209           self.sd=None
210         else:
211           self.sd= sd_prod(etape=self)
212           self.typret=sd_prod
213           # Si la commande est obligatoirement reentrante et reuse n'a pas ete specifie, c'est une erreur. 
214           # On ne fait rien ici. L'erreur sera traitee par la suite. 
215       # précaution
216       if self.sd is not None and not isinstance(self.sd, ASSD):
217          raise AsException("""
218 Impossible de typer le résultat !
219 Causes possibles :
220    Utilisateur : Soit la valeur fournie derrière "reuse" est incorrecte,
221                  soit il y a une "," à la fin d'une commande précédente.
222    Développeur : La fonction "sd_prod" retourne un type invalide.""")
223       return self.sd
224
225    def get_type_produit(self,force=0):
226       try:
227           return self.get_type_produit_brut(force)
228       except:
229           #traceback.print_exc()
230           return None
231
232    def get_type_produit_brut(self,force=0):
233       """
234            Retourne le type du concept résultat de l'étape et eventuellement type
235            les concepts produits "à droite" du signe égal (en entrée)
236
237            Deux cas :
238              - cas 1 : sd_prod de oper n'est pas une fonction
239                     il s'agit d'une sous classe de ASSD
240                     on retourne le nom de la classe
241              - cas 2 : il s'agit d'une fonction
242                     on l'évalue avec les mots-clés de l'étape (mc_liste)
243                     et on retourne son résultat
244       """
245       if not force and hasattr(self,'typret'): return self.typret
246       # On marque les concepts CO pour verification ulterieure de leur bonne utilisation
247       self.mark_CO()
248
249       if type(self.definition.sd_prod) == types.FunctionType:
250         d=self.cree_dict_valeurs(self.mc_liste)
251         # Comme sd_prod peut invoquer la méthode type_sdprod qui ajoute
252         # les concepts produits dans self.sdprods, il faut le mettre à zéro
253         self.sdprods=[]
254         sd_prod= apply(self.definition.sd_prod,(self,),d)
255       else:
256         sd_prod=self.definition.sd_prod
257       return sd_prod
258
259    def get_contexte_avant(self,etape):
260       """
261           Retourne le dictionnaire des concepts connus avant etape
262           pour les commandes internes a la macro
263           On tient compte des commandes qui modifient le contexte
264           comme DETRUIRE ou les macros
265       """
266       # L'étape courante pour laquelle le contexte a été calculé est 
267       # mémorisée dans self.index_etape_courante
268       # Si on insère des commandes (par ex, dans EFICAS), il faut
269       # préalablement remettre ce pointeur à 0
270       if etape:
271          index_etape=self.etapes.index(etape)
272       else:
273          index_etape=len(self.etapes)
274
275       if index_etape >= self.index_etape_courante:
276          # On calcule le contexte en partant du contexte existant
277          d=self.current_context
278          liste_etapes=self.etapes[self.index_etape_courante:index_etape]
279       else:
280          d=self.current_context={}
281          liste_etapes=self.etapes
282
283       for e in liste_etapes:
284         if e is etape:
285            break
286         if e.isactif():
287            e.update_context(d)
288       self.index_etape_courante=index_etape
289       return d
290
291    def supprime(self):
292       """
293          Méthode qui supprime toutes les références arrières afin que 
294          l'objet puisse etre correctement détruit par le garbage collector
295       """
296       N_MCCOMPO.MCCOMPO.supprime(self)
297       self.jdc=None
298       self.appel=None
299       if self.sd : self.sd.supprime()
300       for concept in self.sdprods:
301          concept.supprime()
302       for etape in self.etapes:
303          etape.supprime()
304
305    def type_sdprod(self,co,t):
306       """
307            Cette methode a pour fonction de typer le concept co avec le type t
308            dans les conditions suivantes :
309             1. co est un concept produit de self
310             2. co est un concept libre : on le type et on l attribue à self
311
312            Elle enregistre egalement les concepts produits (on fait l hypothese
313            que la liste sdprods a été correctement initialisee, vide probablement)
314       """
315       if not hasattr(co,'etape'):
316          # Le concept vaut None probablement. On ignore l'appel
317          return
318       # 
319       # On cherche a discriminer les differents cas de typage d'un concept
320       # produit par une macro qui est specifie dans un mot cle simple.
321       # On peut passer plusieurs fois par type_sdprod ce qui explique
322       # le nombre important de cas.
323       #
324       # Cas 1 : Le concept est libre. Il vient d'etre cree par CO(nom)
325       # Cas 2 : Le concept est produit par la macro. On est deja passe par type_sdprod.
326       #         Cas semblable a Cas 1.
327       # Cas 3 : Le concept est produit par la macro englobante (parent). On transfere
328       #         la propriete du concept de la macro parent a la macro courante (self)
329       #         en verifiant que le type est valide
330       # Cas 4 : La concept est la propriete d'une etape fille. Ceci veut dire qu'on est
331       #         deja passe par type_sdprod et que la propriete a ete transfere a une 
332       #         etape fille. Cas semblable a Cas 3.
333       # Cas 5 : Le concept est produit par une etape externe a la macro.
334       #
335       if co.etape == None:
336          # Cas 1 : le concept est libre
337          # On l'attache a la macro et on change son type dans le type demande
338          # Recherche du mot cle simple associe au concept
339          mcs=self.get_mcs_with_co(co)
340          if len(mcs) != 1:
341             raise AsException("""Erreur interne. 
342 Il ne devrait y avoir qu'un seul mot cle porteur du concept CO (%s)""" % co)
343          mcs=mcs[0]
344          if not self.typeCO in mcs.definition.type:
345             raise AsException("""Erreur interne. 
346 Impossible de changer le type du concept (%s). Le mot cle associe ne supporte pas CO mais seulement (%s)""" %(co,mcs.definition.type))
347          co.etape=self
348          # affectation du bon type du concept et
349          # initialisation de sa partie "sd"
350          if CONTEXT.debug:print "changement de type:",co,t
351          co.change_type(t)
352          
353          self.sdprods.append(co)
354
355       elif co.etape== self:
356          # Cas 2 : le concept est produit par la macro (self)
357          # On est deja passe par type_sdprod (Cas 1 ou 3).
358          if co.etape==co._etape:
359            #Le concept a été créé par la macro (self)
360            #On peut changer son type
361            co.change_type(t)
362          else:
363            #Le concept a été créé par une macro parente
364            # Le type du concept doit etre coherent avec le type demande (seulement derive)
365            if not isinstance(co,t):
366              raise AsException("""Erreur interne. 
367 Le type demande (%s) et le type du concept (%s) devraient etre derives""" %(t,co.__class__))
368
369          self.sdprods.append(co)
370
371       elif co.etape== self.parent:
372          # Cas 3 : le concept est produit par la macro parente (self.parent)
373          # on transfere la propriete du concept a la macro fille
374          # et on change le type du concept comme demande
375          # Au prealable, on verifie que le concept existant (co) est une instance 
376          # possible du type demande (t)
377          # Cette règle est normalement cohérente avec les règles de vérification des mots-clés
378          if not isinstance(co,t):
379             raise AsException("""
380 Impossible de changer le type du concept produit (%s) en (%s).
381 Le type actuel (%s) devrait etre une classe derivee du nouveau type (%s)""" % (co,t,co.__class__,t))
382          mcs=self.get_mcs_with_co(co)
383          if len(mcs) != 1:
384             raise AsException("""Erreur interne. 
385 Il ne devrait y avoir qu'un seul mot cle porteur du concept CO (%s)""" % co)
386          mcs=mcs[0]
387          if not self.typeCO in mcs.definition.type:
388             raise AsException("""Erreur interne. 
389 Impossible de changer le type du concept (%s). Le mot cle associe ne supporte pas CO mais seulement (%s)""" %(co,mcs.definition.type))
390          co.etape=self
391          # On ne change pas le type car il respecte la condition isinstance(co,t)
392          #co.__class__ = t
393          self.sdprods.append(co)
394
395       elif self.issubstep(co.etape):
396          # Cas 4 : Le concept est propriété d'une sous etape de la macro (self). 
397          # On est deja passe par type_sdprod (Cas 3 ou 1).
398          # Il suffit de le mettre dans la liste des concepts produits (self.sdprods)
399          # Le type du concept et t doivent etre derives. 
400          # Il n'y a aucune raison pour que la condition ne soit pas verifiee.
401          if not isinstance(co,t):
402             raise AsException("""Erreur interne. 
403 Le type demande (%s) et le type du concept (%s) devraient etre derives""" %(t,co.__class__))
404          self.sdprods.append(co)
405
406       else:
407          # Cas 5 : le concept est produit par une autre étape
408          # On ne fait rien
409          return
410
411    def issubstep(self,etape):
412       """ 
413           Cette methode retourne un entier indiquant si etape est une
414           sous etape de la macro self ou non
415           1 = oui
416           0 = non
417       """
418       if etape in self.etapes:return 1
419       for etap in self.etapes:
420         if etap.issubstep(etape):return 1
421       return 0
422
423    def register(self,etape):
424       """ 
425           Enregistrement de etape dans le contexte de la macro : liste etapes 
426           et demande d enregistrement global aupres du JDC
427       """
428       self.etapes.append(etape)
429       idetape=self.jdc.g_register(etape)
430       return idetape
431
432    def reg_sd(self,sd):
433       """ 
434            Methode appelee dans l __init__ d un ASSD a sa creation pour
435            s enregistrer (reserve aux ASSD créés au sein d'une MACRO)
436       """
437       self.sds.append(sd)
438       return self.jdc.o_register(sd)
439
440    def create_sdprod(self,etape,nomsd):
441       """ 
442           Cette methode doit fabriquer le concept produit retourne
443           par l'etape etape et le nommer.
444
445           Elle est appelée à l'initiative de l'etape
446           pendant le processus de construction de cette etape : methode __call__
447           de la classe CMD (OPER ou MACRO)
448           Ce travail est réalisé par le contexte supérieur (etape.parent)
449           car dans certains cas, le concept ne doit pas etre fabriqué mais
450           l'etape doit simplement utiliser un concept préexistant.
451                   - Cas 1 : etape.reuse != None : le concept est réutilisé
452                   - Cas 2 : l'étape appartient à une macro qui a déclaré un concept
453                     de sortie qui doit etre produit par cette etape.
454       """
455       if self.Outputs.has_key(nomsd):
456          # Il s'agit d'un concept de sortie de la macro. Il ne faut pas le créer
457          # Il faut quand meme appeler la fonction sd_prod si elle existe.
458          # get_type_produit le fait et donne le type attendu par la commande pour verification ultérieure.
459          sdprod=etape.get_type_produit_brut()
460          sd=self.Outputs[nomsd]
461          # On verifie que le type du concept existant sd.__class__ est un sur type de celui attendu
462          # Cette règle est normalement cohérente avec les règles de vérification des mots-clés
463          if not issubclass(sdprod,sd.__class__):
464             raise AsException("Le type du concept produit %s devrait etre une sur classe de %s" %(sd.__class__,sdprod))
465          # La propriete du concept est transferee a l'etape avec le type attendu par l'étape
466          etape.sd=sd
467          sd.etape=etape
468          # On donne au concept le type produit par la sous commande.
469          # Le principe est le suivant : apres avoir verifie que le type deduit par la sous commande
470          # est bien coherent avec celui initialement affecte par la macro (voir ci dessus)
471          # on affecte au concept ce type car il peut etre plus precis (derive, en general)
472          sd.__class__=sdprod
473          # On force également le nom stocké dans l'attribut sdnom : on lui donne le nom 
474          # du concept associé à nomsd
475          etape.sdnom=sd.nom
476       elif etape.definition.reentrant != 'n' and etape.reuse != None:
477          # On est dans le cas d'une commande avec reutilisation d'un concept existant
478          # get_sd_prod fait le necessaire : verifications, associations, etc. mais ne cree 
479          # pas un nouveau concept. Il retourne le concept reutilise
480          sd= etape.get_sd_prod()
481          # Dans le cas d'un concept nomme automatiquement : _xxx, __xxx,
482          # On force le nom stocke dans l'attribut sdnom  de l'objet etape : on lui donne le nom 
483          # du concept  reutilise (sd ou etape.reuse c'est pareil)
484          # Ceci est indispensable pour eviter des erreurs lors des verifications des macros
485          # En effet une commande avec reutilisation d'un concept verifie que le nom de 
486          # la variable a gauche du signe = est le meme que celui du concept reutilise.
487          # Lorsqu'une telle commande apparait dans une macro, on supprime cette verification.
488          if (etape.sdnom == '' or etape.sdnom[0] == '_'):
489             etape.sdnom=sd.nom
490       else:
491          # On est dans le cas de la creation d'un nouveau concept
492          sd= etape.get_sd_prod()
493          if sd != None :
494             self.NommerSdprod(sd,nomsd)
495       return sd
496
497    def NommerSdprod(self,sd,sdnom,restrict='non'):
498       """ 
499           Cette methode est appelee par les etapes internes de la macro
500           La macro appelle le JDC pour valider le nommage
501           On considere que l espace de nom est unique et géré par le JDC
502           Si le nom est deja utilise, l appel leve une exception
503           Si restrict=='non', on insere le concept dans le contexte de la macro
504           Si restrict=='oui', on n'insere pas le concept dans le contexte de la macro
505       """
506       # Normalement, lorsqu'on appelle cette methode, on ne veut nommer que des concepts nouvellement crees.
507       # Le filtrage sur les concepts a creer ou a ne pas creer est fait dans la methode
508       # create_sdprod. La seule chose a verifier apres conversion eventuelle du nom
509       # est de verifier que le nom n'est pas deja attribue. Ceci est fait en delegant
510       # au JDC par l'intermediaire du parent.
511
512       #XXX attention inconsistence : prefix et gcncon ne sont pas 
513       # définis dans le package Noyau. La methode NommerSdprod pour
514       # les macros devrait peut etre etre déplacée dans Build ???
515
516       if CONTEXT.debug : print "MACRO.NommerSdprod: ",sd,sdnom
517
518       if hasattr(self,'prefix'):
519         # Dans le cas de l'include_materiau on ajoute un prefixe au nom du concept
520         if sdnom != self.prefix:sdnom=self.prefix+sdnom
521
522       if self.Outputs.has_key(sdnom):
523         # Il s'agit d'un concept de sortie de la macro produit par une sous commande
524         sdnom=self.Outputs[sdnom].nom
525       elif sdnom != '' and sdnom[0] == '_':
526         # Si le nom du concept commence par le caractere _ on lui attribue
527         # un identificateur JEVEUX construit par gcncon et respectant
528         # la regle gcncon legerement adaptee ici
529         # nom commencant par __ : il s'agit de concepts qui seront detruits
530         # nom commencant par _ : il s'agit de concepts intermediaires qui seront gardes
531         # ATTENTION : il faut traiter différemment les concepts dont le nom
532         # commence par _ mais qui sont des concepts nommés automatiquement par
533         # une éventuelle sous macro.
534         # Le test suivant n'est pas tres rigoureux mais permet de fonctionner pour le moment (a améliorer)
535         if sdnom[1] in string.digits:
536           # Ce concept provient probablement d'une macro appelee par self
537           pass
538         elif sdnom[1] == '_':
539           sdnom=self.gcncon('.')
540         else:
541           sdnom=self.gcncon('_')
542       else:
543         # On est dans le cas d'un nom de concept global. 
544         pass
545
546       if restrict == 'non':
547          # On demande le nommage au parent mais sans ajout du concept dans le contexte du parent
548          # car on va l'ajouter dans le contexte de la macro
549          self.parent.NommerSdprod(sd,sdnom,restrict='oui')
550          # On ajoute dans le contexte de la macro les concepts nommes
551          # Ceci est indispensable pour les CO (macro) dans un INCLUDE
552          self.g_context[sdnom]=sd
553       else:
554          # La demande de nommage vient probablement d'une macro qui a mis
555          # le concept dans son contexte. On ne traite plus que le nommage (restrict="oui")
556          self.parent.NommerSdprod(sd,sdnom,restrict='oui')
557
558    def delete_concept_after_etape(self,etape,sd):
559       """
560           Met à jour les étapes de la MACRO  qui sont après etape suite à
561           la disparition du concept sd
562       """
563       # Cette methode est définie dans le noyau mais ne sert que pendant la phase de creation
564       # des etapes et des concepts. Il n'y a aucun traitement particulier à réaliser
565       # Dans d'autres conditions, il faudrait surcharger cette méthode.
566       return
567
568    def accept(self,visitor):
569       """
570          Cette methode permet de parcourir l'arborescence des objets
571          en utilisant le pattern VISITEUR
572       """
573       visitor.visitMACRO_ETAPE(self)
574
575    def update_context(self,d):
576       """
577          Met à jour le contexte contenu dans le dictionnaire d
578          Une MACRO_ETAPE peut ajouter plusieurs concepts dans le contexte
579          Une fonction enregistree dans op_init peut egalement modifier le contexte
580       """
581       if type(self.definition.op_init) == types.FunctionType:
582         apply(self.definition.op_init,(self,d))
583       if self.sd != None:d[self.sd.nom]=self.sd
584       for co in self.sdprods:
585         d[co.nom]=co
586
587    def make_include(self,unite=None):
588       """
589           Inclut un fichier dont l'unite logique est unite
590       """
591       if not unite : return
592       f,text=self.get_file(unite=unite,fic_origine=self.parent.nom)
593       self.fichier_init = f
594       if f == None:return
595       self.make_contexte(f,text)
596
597    def make_poursuite(self):
598       """
599           Inclut un fichier poursuite
600       """
601       try:
602          f,text=self.get_file(fic_origine=self.parent.nom)
603       except:
604          raise AsException("Impossible d'ouvrir la base pour une poursuite")
605       self.fichier_init=f
606       if f == None:return
607       self.make_contexte(f,text)
608
609    def make_contexte(self,f,text):
610       """
611           Interprete le texte fourni (text) issu du fichier f
612           dans le contexte du parent.
613           Cette methode est utile pour le fonctionnement des
614           INCLUDE
615       """
616       # on execute le texte fourni dans le contexte forme par
617       # le contexte de l etape pere (global au sens Python)
618       # et le contexte de l etape (local au sens Python)
619       code=compile(text,f,'exec')
620       d={}
621       self.g_context = d
622       self.contexte_fichier_init = d
623       globs=self.parent.get_global_contexte()
624       exec code in globs,d
625
626    def get_global_contexte(self):
627       """
628           Cette methode retourne le contexte global fourni
629           par le parent(self) a une etape fille (l'appelant) pour
630           realiser des evaluations de texte Python (INCLUDE,...)
631       """
632       # Le contexte global est forme par concatenation du contexte
633       # du parent de self et de celui de l'etape elle meme (self)
634       d=self.parent.get_global_contexte()
635       d.update(self.g_context)
636       return d
637
638    def copy(self):
639       """ Méthode qui retourne une copie de self non enregistrée auprès du JDC
640           et sans sd
641           On surcharge la methode de ETAPE pour exprimer que les concepts crees
642           par la MACRO d'origine ne sont pas crees par la copie mais eventuellement
643           seulement utilises
644       """
645       etape=N_ETAPE.ETAPE.copy(self)
646       etape.sdprods=[]
647       return etape
648
649    def copy_intern(self,etape):
650       """ Cette méthode effectue la recopie des etapes internes d'une macro 
651           passée en argument (etape)
652       """
653       self.etapes=[]
654       for etp in etape.etapes:
655           new_etp=etp.copy()
656           new_etp.copy_reuse(etp)
657           new_etp.copy_sdnom(etp)
658           new_etp.reparent(self)
659           if etp.sd:
660              new_sd = etp.sd.__class__(etape=new_etp)
661              new_etp.sd = new_sd
662              if etp.reuse:
663                 new_sd.set_name(etp.sd.nom)
664              else:
665                 self.NommerSdprod(new_sd,etp.sd.nom)
666           new_etp.copy_intern(etp)
667           self.etapes.append(new_etp)
668
669    def reset_jdc(self,new_jdc):
670        """
671           Reinitialise l'etape avec un nouveau jdc parent new_jdc
672        """
673        if self.sd and self.reuse == None :
674            self.parent.NommerSdprod(self.sd,self.sd.nom)
675        for concept in self.sdprods:
676            self.parent.NommerSdprod(concept,concept.nom)
677
678    def reparent(self,parent):
679        """
680          Cette methode sert a reinitialiser la parente de l'objet
681        """
682        N_ETAPE.ETAPE.reparent(self,parent)
683        #on ne change pas la parenté des concepts. On s'assure uniquement que le jdc en référence est le bon
684        for concept in self.sdprods:
685            concept.jdc=self.jdc
686        for e in self.etapes:
687            e.reparent(self)