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