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