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