Salome HOME
9045037f5d0137ca2280eafde939ccd06e352720
[tools/eficas.git] / Ihm / I_MACRO_ETAPE.py
1 #            CONFIGURATION MANAGEMENT OF EDF VERSION
2 # ======================================================================
3 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
4 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
5 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
6 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
7 # (AT YOUR OPTION) ANY LATER VERSION.
8 #
9 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
10 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
11 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
12 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
13 #
14 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
15 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
16 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
17 #
18 #
19 # ======================================================================
20 """
21 """
22 # Modules Python
23 import sys
24 import traceback,types,string
25
26 # Modules Eficas
27 import I_ETAPE
28 from Noyau.N_ASSD import ASSD
29
30 # import rajoutés suite à l'ajout de Build_sd --> à résorber
31 import Noyau, Validation.V_MACRO_ETAPE
32 from Noyau import N_Exception
33 from Noyau.N_Exception import AsException
34 # fin import à résorber
35
36 class MACRO_ETAPE(I_ETAPE.ETAPE):
37
38   def __init__(self):
39       self.typret=None
40       self.recorded_units={}
41
42   def get_sdprods(self,nom_sd):
43     """ 
44          Fonction : retourne le concept produit par l etape de nom nom_sd
45                     s il existe sinon None
46     """
47     if self.sd and self.sd.nom == nom_sd :return self.sd
48     for co in self.sdprods:
49       if co.nom == nom_sd:return co
50     if type(self.definition.op_init) == types.FunctionType:
51       d={}
52       apply(self.definition.op_init,(self,d))
53       return d.get(nom_sd,None)
54     return None
55
56   def get_contexte_jdc(self,fichier,text):
57     """ 
58          Interprète text comme un texte de jdc et retourne le 
59          contexte final
60          cad le dictionnaire des sd disponibles à la dernière étape
61          Si text n'est pas un texte de jdc valide, retourne None
62          ou leve une exception
63          --> utilisée par ops.POURSUITE et INCLUDE
64     """
65     try:
66        # on essaie de créer un objet JDC auxiliaire avec un contexte initial
67        context_ini = self.parent.get_contexte_avant(self)
68
69        # Indispensable avant de creer un nouveau JDC
70        CONTEXT.unset_current_step()
71        args=self.jdc.args
72        prefix_include=None
73        if hasattr(self,'prefix'):
74           prefix_include=self.prefix
75        # ATTENTION : le dictionnaire recorded_units sert à memoriser les unites des 
76        # fichiers inclus. Il est preferable de garder le meme dictionnaire pendant
77        # tout le traitement et de ne pas le reinitialiser brutalement (utiliser clear plutot)
78        # si on ne veut pas perdre la memoire des unites.
79        # En principe si la memorisation est faite au bon moment il n'est pas necessaire
80        # de prendre cette precaution mais ce n'est pas vrai partout.
81        old_recorded_units=self.recorded_units.copy()
82        self.recorded_units.clear()
83
84        j=self.JdC_aux( procedure=text,cata=self.jdc.cata,
85                                 nom=fichier,
86                                 context_ini = context_ini,
87                                 appli=self.jdc.appli,
88                                 jdc_pere=self.jdc,etape_include=self,
89                                 prefix_include=prefix_include,
90                                 recorded_units=self.recorded_units,
91                                 old_recorded_units=old_recorded_units,**args)
92
93        j.analyse()
94        # On récupère les étapes internes (pour validation)
95        self.etapes=j.etapes
96     except:
97        traceback.print_exc()
98        # On force le contexte (etape courante) à self
99        CONTEXT.unset_current_step()
100        CONTEXT.set_current_step(self)
101        return None
102
103     if not j.cr.estvide():
104        # Erreurs dans l'INCLUDE. On garde la memoire du fichier mais on n'insere pas les concepts
105        # On force le contexte (etape courante) à self
106        CONTEXT.unset_current_step()
107        CONTEXT.set_current_step(self)
108        raise Exception("Impossible de relire le fichier\n"+str(j.cr))
109
110     cr=j.report()
111     if not cr.estvide():
112        # On force le contexte (etape courante) à self
113        CONTEXT.unset_current_step()
114        CONTEXT.set_current_step(self)
115        raise Exception("Le fichier include contient des erreurs\n"+str(j.cr))
116
117     # On recupere le contexte apres la derniere etape
118     j_context=j.get_contexte_avant(None)
119
120     # Cette verification n'est plus necessaire elle est integree dans le JDC_INCLUDE
121     self.verif_contexte(j_context)
122
123     # On remplit le dictionnaire des concepts produits inclus
124     # en retirant les concepts présents dans le  contexte initial
125     # On ajoute egalement le concept produit dans le sds_dict du parent
126     # sans verification car on est sur (verification integrée) que le nommage est possible
127     self.g_context.clear()
128     for k,v in j_context.items():
129        if not context_ini.has_key(k) or context_ini[k] != v:
130            self.g_context[k]=v
131            self.parent.sds_dict[k]=v
132
133
134     # On recupere le contexte courant
135     self.current_context=j.current_context
136     self.index_etape_courante=j.index_etape_courante
137
138     # XXX j.supprime() ???
139     # On rétablit le contexte (etape courante) à self
140     CONTEXT.unset_current_step()
141     CONTEXT.set_current_step(self)
142
143     return j_context
144
145   def verif_contexte(self,context):
146      """
147          On verifie que le contexte context peut etre inséré dans le jeu
148          de commandes à la position de self
149      """
150      for nom_sd,sd in context.items():
151         if not isinstance(sd,ASSD):continue
152         #if self.parent.get_sd_apres_etape(nom_sd,etape=self):
153         if self.parent.get_sd_apres_etape_avec_detruire(nom_sd,sd,etape=self):
154            # Il existe un concept produit par une etape apres self => impossible d'inserer
155            # On force le contexte (etape courante) à self
156            CONTEXT.unset_current_step()
157            CONTEXT.set_current_step(self)
158            raise Exception("Impossible d'inclure le fichier. Un concept de nom " + 
159                            "%s existe déjà dans le jeu de commandes." % nom_sd)
160
161   def reevalue_sd_jdc(self):
162      """
163          Avec la liste des SD qui ont été supprimées, propage la 
164          disparition de ces SD dans toutes les étapes et descendants
165      """
166      l_sd_supp,l_sd_repl = self.diff_contextes()
167      for sd in l_sd_supp:
168         self.parent.delete_concept_after_etape(self,sd)
169      for old_sd,sd in l_sd_repl:
170         self.parent.replace_concept_after_etape(self,old_sd,sd)
171
172   def diff_contextes(self):
173      """ 
174          Réalise la différence entre les 2 contextes 
175          old_contexte_fichier_init et contexte_fichier_init
176          cad retourne la liste des sd qui ont disparu ou ne derivent pas de la meme classe
177          et des sd qui ont ete remplacees
178      """
179      if not hasattr(self,'old_contexte_fichier_init'):return [],[]
180      l_sd_suppressed = []
181      l_sd_replaced = []
182      for old_key in self.old_contexte_fichier_init.keys():
183        if not self.contexte_fichier_init.has_key(old_key):
184          if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
185            l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
186        else:
187          if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
188             # Un concept de meme nom existe
189             old_class=self.old_contexte_fichier_init[old_key].__class__
190             if not isinstance(self.contexte_fichier_init[old_key],old_class):
191                # S'il n'est pas d'une classe derivee, on le supprime
192                l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
193             else:
194                l_sd_replaced.append((self.old_contexte_fichier_init[old_key],self.contexte_fichier_init[old_key]))
195      return l_sd_suppressed,l_sd_replaced
196       
197   def control_sdprods(self,d):
198       """
199           Cette methode doit updater le contexte fournit par
200           l'appelant en argument (d) en fonction de sa definition
201           tout en verifiant que ses concepts produits ne sont pas
202           deja definis dans le contexte
203       """
204       if hasattr(self,"fichier_unite"):
205          self.update_fichier_init(self.fichier_unite)
206          self.init_modif()
207
208       if type(self.definition.op_init) == types.FunctionType:
209         apply(self.definition.op_init,(self,d))
210       if self.sd:
211         if d.has_key(self.sd.nom):
212            # Le concept est deja defini
213            if self.reuse and self.reuse is d[self.sd.nom]:
214               # Le concept est reutilise : situation normale
215               pass
216            else:
217               # Redefinition du concept, on l'annule
218               #XXX on pourrait simplement annuler son nom pour conserver les objets
219               # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
220               self.sd=self.reuse=self.sdnom=None
221               self.init_modif()
222         else:
223            # Le concept n'est pas defini, on peut updater d
224            d[self.sd.nom]=self.sd
225       # On verifie les concepts a droite du signe =
226       for co in self.sdprods:
227         if d.has_key(co.nom) and co is not d[co.nom] :
228            self.delete_concept(co)
229         else:
230            d[co.nom]=co
231        
232
233   def supprime_sdprods(self):
234       """
235           Fonction:
236             Lors d'une destruction d'etape, detruit tous les concepts produits
237             Un opérateur n a qu un concept produit
238             Une procedure n'en a aucun
239             Une macro en a en général plus d'un
240       """
241       if not self.is_reentrant() :
242          # l'étape n'est pas réentrante
243          # le concept retourné par l'étape est à supprimer car il était
244          # créé par l'étape
245          if self.sd != None :
246             self.parent.del_sdprod(self.sd)
247             self.parent.delete_concept(self.sd)
248       # On détruit les concepts à droite du signe =
249       for co in self.sdprods:
250          self.parent.del_sdprod(co)
251          self.parent.delete_concept(co)
252       # Si la macro a des etapes et des concepts inclus, on les detruit
253       for nom_sd,co in self.g_context.items():
254          if not isinstance(co,ASSD):continue
255          self.parent.del_sdprod(co)
256          self.parent.delete_concept(co)
257       # On met g_context à blanc
258       self.g_context={}
259          
260 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
261   def Build_sd(self,nom):
262      """
263         Construit le concept produit de l'opérateur. Deux cas 
264         peuvent se présenter :
265
266         - le parent n'est pas défini. Dans ce cas, l'étape prend en charge 
267           la création et le nommage du concept.
268
269         - le parent est défini. Dans ce cas, l'étape demande au parent la 
270           création et le nommage du concept.
271
272      """
273      if not self.isactif():return
274      # CCAR : meme modification que dans I_ETAPE
275      if not self.isvalid(sd='non') : return
276      self.sdnom=nom
277      try:
278         # On positionne la macro self en tant que current_step pour que les 
279         # étapes créées lors de l'appel à sd_prod et à op_init aient la macro
280         #  comme parent 
281         self.set_current_step()
282         if self.parent:
283            sd= self.parent.create_sdprod(self,nom)
284            if type(self.definition.op_init) == types.FunctionType: 
285               apply(self.definition.op_init,(self,self.parent.g_context))
286         else:
287            sd=self.get_sd_prod()
288            if sd != None and self.reuse == None:
289               # On ne nomme le concept que dans le cas de non reutilisation 
290               # d un concept
291               sd.nom=nom
292         self.reset_current_step()
293         # Si on est arrive ici, l'etape est valide
294         self.state="unchanged"
295         self.valid=1
296         if self.jdc and self.jdc.par_lot == "NON" :
297            self.Execute()
298         return sd
299      except AsException,e:
300         self.reset_current_step()
301         # Une erreur s'est produite lors de la construction du concept
302         # Comme on est dans EFICAS, on essaie de poursuivre quand meme
303         # Si on poursuit, on a le choix entre deux possibilités :
304         # 1. on annule la sd associée à self
305         # 2. on la conserve mais il faut qu'elle soit correcte et la retourner
306         # En plus il faut rendre coherents sdnom et sd.nom
307         # On choisit de retourner None et de mettre l'etape invalide 
308         self.sd=None
309         self.sdnom=None
310         self.state="unchanged"
311         self.valid=0
312         return self.sd
313         #raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
314         #                     'fichier : ',self.appel[1],e)
315      except EOFError:
316         raise
317      except :
318         self.reset_current_step()
319         l=traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2])
320         raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
321                           'fichier : ',self.appel[1]+'\n',
322                            string.join(l))
323
324   def make_contexte_include(self,fichier,text):
325     """
326         Cette méthode sert à créer un contexte en interprétant un texte source
327         Python
328     """
329     # on récupère le contexte d'un nouveau jdc dans lequel on interprete text
330     contexte = self.get_contexte_jdc(fichier,text)
331     if contexte == None :
332       raise Exception("Impossible de construire le jeu de commandes correspondant au fichier")
333     else:
334       # Pour les macros de type include : INCLUDE, INCLUDE_MATERIAU et POURSUITE
335       # l'attribut g_context est un dictionnaire qui contient les concepts produits par inclusion
336       # l'attribut contexte_fichier_init est un dictionnaire qui contient les concepts produits
337       # en sortie de macro. g_context est obtenu en retirant de contexte_fichier_init les concepts
338       # existants en debut de macro contenus dans context_ini (dans get_contexte_jdc)
339       # g_context est utilisé pour avoir les concepts produits par la macro
340       # contexte_fichier_init est utilisé pour avoir les concepts supprimés par la macro
341       self.contexte_fichier_init = contexte
342
343   def reevalue_fichier_init(self):
344       """Recalcule les concepts produits par le fichier enregistre"""
345       old_context=self.contexte_fichier_init
346       try:
347          self.make_contexte_include(self.fichier_ini ,self.fichier_text)
348       except:
349          l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
350          self.fichier_err = string.join(l)
351          #self.etapes=[]
352          self.g_context={}
353
354          self.old_contexte_fichier_init=old_context
355          self.contexte_fichier_init={}
356          self.reevalue_sd_jdc()
357          return
358
359       # L'evaluation s'est bien passee
360       self.fichier_err = None
361       self.old_contexte_fichier_init=old_context
362       self.reevalue_sd_jdc()
363
364   def update_fichier_init(self,unite):
365       """Reevalue le fichier init sans demander (dans la mesure du possible) a l'utilisateur 
366          les noms des fichiers
367          Ceci suppose que les relations entre unites et noms ont été memorisees préalablement
368       """
369       
370       self.fichier_err=None
371       self.old_contexte_fichier_init=self.contexte_fichier_init
372
373       if unite != self.fichier_unite or not self.parent.recorded_units.has_key(unite):
374          # Changement d'unite ou Nouvelle unite
375          f,text=self.get_file(unite=unite,fic_origine=self.parent.nom)
376          units={}
377          if f is not None:
378             self.fichier_ini = f
379             self.fichier_text=text
380          self.recorded_units=units
381          if self.fichier_ini is None and self.jdc.appli:
382             self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
383                      message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
384       else:
385          # Meme unite existante
386          f,text,units=self.parent.recorded_units[unite]
387          self.fichier_ini = f
388          self.fichier_text=text
389          self.recorded_units=units
390
391       if self.fichier_ini is None:
392          # Le fichier n'est pas défini
393          self.fichier_err="Le fichier associé n'est pas défini"
394          self.parent.change_unit(unite,self,self.fichier_unite)
395          self.g_context={}
396          self.contexte_fichier_init={}
397          self.parent.reset_context()
398          self.reevalue_sd_jdc()
399          return
400
401       try:
402         self.make_contexte_include(self.fichier_ini,self.fichier_text)
403         # Les 3 attributs fichier_ini fichier_text recorded_units doivent etre corrects
404         # avant d'appeler change_unit
405         self.parent.change_unit(unite,self,self.fichier_unite)
406       except:
407         # Erreurs lors de l'evaluation de text dans un JDC auxiliaire
408         l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
409         # On conserve la memoire du nouveau fichier
410         # mais on n'utilise pas les concepts crees par ce fichier
411         # on met l'etape en erreur : fichier_err=string.join(l)
412         self.fichier_err=string.join(l)
413         self.parent.change_unit(unite,self,self.fichier_unite)
414         self.g_context={}
415         self.contexte_fichier_init={}
416
417       # Le contexte du parent doit etre reinitialise car les concepts produits ont changé
418       self.parent.reset_context()
419       # Si des concepts ont disparu lors du changement de fichier, on demande leur suppression
420       self.reevalue_sd_jdc()
421
422   def record_unite(self):
423       if self.nom == "POURSUITE":
424          self.parent.record_unit(None,self)
425       else:
426          if hasattr(self,'fichier_unite') : 
427             self.parent.record_unit(self.fichier_unite,self)
428
429   def make_poursuite(self):
430       """ Cette methode est appelée par la fonction sd_prod de la macro POURSUITE
431       """
432       if not hasattr(self,'fichier_ini') :
433          # Si le fichier n'est pas defini on le demande
434          f,text=self.get_file_memo(fic_origine=self.parent.nom)
435          # On memorise le fichier retourne
436          self.fichier_ini = f
437          self.fichier_unite = None
438          self.fichier_text = text
439          self.fichier_err=None
440          import Extensions.jdc_include
441          self.JdC_aux=Extensions.jdc_include.JdC_poursuite
442          self.contexte_fichier_init={}
443
444          if f is None:
445              self.fichier_err="Le fichier POURSUITE n'est pas defini"
446              self.parent.record_unit(None,self)
447              raise Exception(self.fichier_err)
448
449          try:
450            self.make_contexte_include(self.fichier_ini,self.fichier_text)
451            self.parent.record_unit(None,self)
452          except:
453            l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
454            if self.jdc.appli:
455               self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier poursuite",
456                                             message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
457                                            )
458            self.parent.record_unit(None,self)
459            self.g_context={}
460            self.fichier_err = string.join(l)
461            self.contexte_fichier_init={}
462            raise
463
464       else:
465          # Si le fichier est deja defini on ne reevalue pas le fichier
466          # et on leve une exception si une erreur a été enregistrée
467          self.update_fichier_init(None)
468          if self.fichier_err is not None: raise Exception(self.fichier_err)
469
470   def get_file(self,unite=None,fic_origine=''):
471       """Retourne le nom du fichier et le source correspondant a l'unite unite
472          Initialise en plus recorded_units
473       """
474       units={}
475       if self.jdc :
476          f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
477       else:
478          f,text=None,None
479       self.recorded_units=units
480       return f,text
481
482   def get_file_memo(self,unite=None,fic_origine=''):
483       """Retourne le nom du fichier et le source correspondant a l'unite unite
484          Initialise en plus recorded_units
485       """
486       units={}
487       if self.parent.old_recorded_units.has_key(unite):
488          f,text,units=self.parent.old_recorded_units[unite]
489          self.recorded_units=units
490          return f,text
491       elif self.jdc :
492          f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
493       else:
494          f,text=None,None
495       self.recorded_units=units
496       if f is None and self.jdc.appli:
497          self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
498                           message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
499       return f,text
500
501 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
502   def make_include(self,unite=None):
503       """
504           Inclut un fichier dont l'unite logique est unite
505           Cette methode est appelee par la fonction sd_prod de la macro INCLUDE
506           Si l'INCLUDE est invalide, la methode doit produire une exception 
507           Sinon on retourne None. Les concepts produits par l'INCLUDE sont
508           pris en compte par le JDC parent lors du calcul du contexte (appel de ???)
509       """
510
511       # On supprime l'attribut unite qui bloque l'evaluation du source de l'INCLUDE
512       # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
513       del self.unite
514       # Si unite n'a pas de valeur, l'etape est forcement invalide. On peut retourner None
515       if not unite : return
516
517       if not hasattr(self,'fichier_ini') : 
518          # Si le fichier n'est pas defini on le demande
519          f,text=self.get_file_memo(unite=unite,fic_origine=self.parent.nom)
520          # On memorise le fichier retourne
521          self.fichier_ini  = f
522          self.fichier_text = text
523          self.contexte_fichier_init={}
524          self.fichier_unite=unite
525          self.fichier_err=None
526          import Extensions.jdc_include
527          self.JdC_aux=Extensions.jdc_include.JdC_include
528
529          if f is None:
530              self.fichier_err="Le fichier INCLUDE n est pas defini"
531              self.parent.record_unit(unite,self)
532              raise Exception(self.fichier_err)
533
534          try:
535            self.make_contexte_include(self.fichier_ini ,self.fichier_text)
536            self.parent.record_unit(unite,self)
537          except:
538            l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
539            if self.jdc.appli:
540               self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
541                                             message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
542                                            )
543            self.parent.record_unit(unite,self)
544            self.g_context={}
545            self.fichier_err = string.join(l)
546            self.contexte_fichier_init={}
547            raise
548
549       else:
550          # Si le fichier est deja defini on ne reevalue pas le fichier
551          # et on leve une exception si une erreur a été enregistrée
552          self.update_fichier_init(unite)
553          self.fichier_unite=unite
554          if self.fichier_err is not None: raise Exception(self.fichier_err)
555         
556
557 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
558   def make_contexte(self,fichier,text):
559     """
560         Cette méthode sert à créer un contexte pour INCLUDE_MATERIAU
561         en interprétant un texte source Python
562         Elle est appelee par la fonction sd_prd d'INCLUDE_MATERIAU
563     """
564     # On supprime l'attribut mat qui bloque l'evaluation du source de l'INCLUDE_MATERIAU
565     # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
566     if hasattr(self,'mat'):del self.mat
567     self.fichier_ini =fichier
568     self.fichier_unite =fichier
569     self.fichier_text=text
570     self.fichier_err=None 
571     self.contexte_fichier_init={}
572     # On specifie la classe a utiliser pour le JDC auxiliaire
573     import Extensions.jdc_include
574     self.JdC_aux=Extensions.jdc_include.JdC_include
575     try:
576        self.make_contexte_include(self.fichier_ini ,self.fichier_text)
577        self.parent.record_unit(self.fichier_unite,self)
578     except:
579        l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
580        self.fichier_err = string.join(l)
581        self.parent.record_unit(self.fichier_unite,self)
582        self.g_context={}
583        self.contexte_fichier_init={}
584        raise
585
586 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
587   def update_sdprod(self,cr='non'):
588      # Cette methode peut etre appelee dans EFICAS avec des mots cles de 
589      # la commande modifies. Ceci peut conduire a la construction ou
590      # a la reconstruction d'etapes dans le cas d'INCLUDE ou d'INCLUDE_MATERIAU
591      # Il faut donc positionner le current_step avant l'appel
592      CONTEXT.unset_current_step()
593      CONTEXT.set_current_step(self)
594      valid=Validation.V_MACRO_ETAPE.MACRO_ETAPE.update_sdprod(self,cr=cr)
595      CONTEXT.unset_current_step()
596      return valid
597