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.
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.
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.
19 # ======================================================================
24 import traceback,types,string
28 from Noyau.N_ASSD import ASSD
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
36 class MACRO_ETAPE(I_ETAPE.ETAPE):
41 def get_sdprods(self,nom_sd):
43 Fonction : retourne le concept produit par l etape de nom nom_sd
44 s il existe sinon None
46 if self.sd and self.sd.nom == nom_sd :return self.sd
47 for co in self.sdprods:
48 if co.nom == nom_sd:return co
49 if type(self.definition.op_init) == types.FunctionType:
51 apply(self.definition.op_init,(self,d))
52 return d.get(nom_sd,None)
55 def get_contexte_jdc(self,fichier,text):
57 Interprète text comme un texte de jdc et retourne le
59 cad le dictionnaire des sd disponibles à la dernière étape
60 Si text n'est pas un texte de jdc valide, retourne None
62 --> utilisée par ops.POURSUITE et INCLUDE
65 # on essaie de créer un objet JDC auxiliaire avec un contexte initial
66 context_ini = self.parent.get_contexte_avant(self)
68 # Indispensable avant de creer un nouveau JDC
69 CONTEXT.unset_current_step()
72 if hasattr(self,'prefix'):
73 prefix_include=self.prefix
75 j=self.JdC_aux( procedure=text,cata=self.jdc.cata,
77 context_ini = context_ini,
79 jdc_pere=self.jdc,etape_include=self,
80 prefix_include=prefix_include,**args)
85 # On force le contexte (etape courante) à self
86 CONTEXT.unset_current_step()
87 CONTEXT.set_current_step(self)
90 if not j.cr.estvide():
91 # On force le contexte (etape courante) à self
92 CONTEXT.unset_current_step()
93 CONTEXT.set_current_step(self)
94 # Erreurs dans l'INCLUDE. On garde la memoire du fichier mais on n'insere pas les concepts
95 # et les etapes. Ce traitement doit etre fait par l'appelant qui recoit l'exception
96 raise Exception("Impossible de relire le fichier\n"+str(j.cr))
100 # On force le contexte (etape courante) à self
101 CONTEXT.unset_current_step()
102 CONTEXT.set_current_step(self)
103 raise Exception("Le fichier include contient des erreurs\n"+str(j.cr))
105 # Cette verification n'est plus necessaire elle est integree dans le JDC_INCLUDE
106 #self.verif_contexte(j_context)
108 # On recupere le contexte apres la derniere etape
109 j_context=j.get_contexte_avant(None)
111 # On remplit le dictionnaire des concepts produits inclus
112 # en retirant les concepts présents dans le contexte initial
113 self.g_context.clear()
114 for k,v in j_context.items():
115 if not context_ini.has_key(k) or context_ini[k] != v:
118 # On récupère les étapes internes (pour validation)
121 # ainsi que le contexte courant
122 self.current_context=j.current_context
123 self.index_etape_courante=j.index_etape_courante
125 # XXX j.supprime() ???
126 # On force le contexte (etape courante) à self
127 CONTEXT.unset_current_step()
128 CONTEXT.set_current_step(self)
132 def verif_contexte(self,context):
134 On verifie que le contexte context peut etre inséré dans le jeu
135 de commandes à la position de self
137 for nom_sd,sd in context.items():
138 if not isinstance(sd,ASSD):continue
139 if self.parent.get_sd_apres_etape(nom_sd,etape=self):
140 # Il existe un concept apres self => impossible d'inserer
141 raise Exception("Impossible d'inclure le fichier. Un concept de nom " +
142 "%s existe déjà dans le jeu de commandes." % nom_sd)
144 def reevalue_sd_jdc(self):
146 Avec la liste des SD qui ont été supprimées, propage la
147 disparition de ces SD dans toutes les étapes et descendants
149 l_sd_supp,l_sd_repl = self.diff_contextes()
151 self.parent.delete_concept_after_etape(self,sd)
152 for old_sd,sd in l_sd_repl:
153 self.parent.replace_concept_after_etape(self,old_sd,sd)
155 def diff_contextes(self):
157 Réalise la différence entre les 2 contextes
158 old_contexte_fichier_init et contexte_fichier_init
159 cad retourne la liste des sd qui ont disparu ou ne derivent pas de la meme classe
160 et des sd qui ont ete remplacees
162 if not hasattr(self,'old_contexte_fichier_init'):return [],[]
165 for old_key in self.old_contexte_fichier_init.keys():
166 if not self.contexte_fichier_init.has_key(old_key):
167 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
168 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
170 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
171 # Un concept de meme nom existe
172 old_class=self.old_contexte_fichier_init[old_key].__class__
173 if not isinstance(self.contexte_fichier_init[old_key],old_class):
174 # S'il n'est pas d'une classe derivee, on le supprime
175 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
177 l_sd_replaced.append((self.old_contexte_fichier_init[old_key],self.contexte_fichier_init[old_key]))
178 return l_sd_suppressed,l_sd_replaced
180 def control_sdprods(self,d):
182 Cette methode doit updater le contexte fournit par
183 l'appelant en argument (d) en fonction de sa definition
184 tout en verifiant que ses concepts produits ne sont pas
185 deja definis dans le contexte
187 if type(self.definition.op_init) == types.FunctionType:
188 apply(self.definition.op_init,(self,d))
190 if d.has_key(self.sd.nom):
191 # Le concept est deja defini
192 if self.reuse and self.reuse is d[self.sd.nom]:
193 # Le concept est reutilise : situation normale
196 # Redefinition du concept, on l'annule
197 #XXX on pourrait simplement annuler son nom pour conserver les objets
198 # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
199 self.sd=self.reuse=self.sdnom=None
202 # Le concept n'est pas defini, on peut updater d
203 d[self.sd.nom]=self.sd
204 # On verifie les concepts a droite du signe =
205 for co in self.sdprods:
206 if d.has_key(co.nom) and co is not d[co.nom] :
207 self.delete_concept(co)
212 def supprime_sdprods(self):
215 Lors d'une destruction d'etape, detruit tous les concepts produits
216 Un opérateur n a qu un concept produit
217 Une procedure n'en a aucun
218 Une macro en a en général plus d'un
220 if not self.is_reentrant() :
221 # l'étape n'est pas réentrante
222 # le concept retourné par l'étape est à supprimer car il était
225 self.parent.del_sdprod(self.sd)
226 self.parent.delete_concept(self.sd)
227 # On détruit les concepts à droite du signe =
228 for co in self.sdprods:
229 self.parent.del_sdprod(co)
230 self.parent.delete_concept(co)
231 # Si la macro a des etapes et des concepts inclus, on les detruit
232 for nom_sd,co in self.g_context.items():
233 if not isinstance(co,ASSD):continue
234 self.parent.del_sdprod(co)
235 self.parent.delete_concept(co)
236 # On met g_context à blanc
239 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
240 def Build_sd(self,nom):
242 Construit le concept produit de l'opérateur. Deux cas
243 peuvent se présenter :
245 - le parent n'est pas défini. Dans ce cas, l'étape prend en charge
246 la création et le nommage du concept.
248 - le parent est défini. Dans ce cas, l'étape demande au parent la
249 création et le nommage du concept.
252 if not self.isactif():return
253 # CCAR : meme modification que dans I_ETAPE
254 if not self.isvalid(sd='non') : return
257 # On positionne la macro self en tant que current_step pour que les
258 # étapes créées lors de l'appel à sd_prod et à op_init aient la macro
260 self.set_current_step()
262 sd= self.parent.create_sdprod(self,nom)
263 if type(self.definition.op_init) == types.FunctionType:
264 apply(self.definition.op_init,(self,self.parent.g_context))
266 sd=self.get_sd_prod()
267 if sd != None and self.reuse == None:
268 # On ne nomme le concept que dans le cas de non reutilisation
271 self.reset_current_step()
272 if self.jdc and self.jdc.par_lot == "NON" :
275 except AsException,e:
276 self.reset_current_step()
277 # Une erreur s'est produite lors de la construction du concept
278 # Comme on est dans EFICAS, on essaie de poursuivre quand meme
279 # Si on poursuit, on a le choix entre deux possibilités :
280 # 1. on annule la sd associée à self
281 # 2. on la conserve mais il faut qu'elle soit correcte et la retourner
282 # En plus il faut rendre coherents sdnom et sd.nom
283 # On choisit de retourner None et de mettre l'etape invalide
286 self.state="unchanged"
289 #raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
290 # 'fichier : ',self.appel[1],e)
294 self.reset_current_step()
295 l=traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2])
296 raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
297 'fichier : ',self.appel[1]+'\n',
300 def make_contexte_include(self,fichier,text):
302 Cette méthode sert à créer un contexte en interprétant un texte source
305 # on récupère le contexte d'un nouveau jdc dans lequel on interprete text
306 contexte = self.get_contexte_jdc(fichier,text)
307 if contexte == None :
308 raise Exception("Impossible de construire le jeu de commandes correspondant au fichier")
310 # Pour les macros de type include : INCLUDE, INCLUDE_MATERIAU et POURSUITE
311 # l'attribut g_context est un dictionnaire qui contient les concepts produits par inclusion
312 # l'attribut contexte_fichier_init est un dictionnaire qui contient les concepts produits
313 # en sortie de macro. g_context est obtenu en retirant de contexte_fichier_init les concepts
314 # existants en debut de macro contenus dans context_ini (dans get_contexte_jdc)
315 # g_context est utilisé pour avoir les concepts produits par la macro
316 # contexte_fichier_init est utilisé pour avoir les concepts supprimés par la macro
317 self.contexte_fichier_init = contexte
319 def reevalue_fichier_init(self):
320 """Recalcule les concepts produits par le fichier enregistre"""
321 old_context=self.contexte_fichier_init
323 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
325 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
326 self.fichier_err = string.join(l)
330 self.old_contexte_fichier_init=old_context
331 self.contexte_fichier_init={}
332 self.reevalue_sd_jdc()
335 # L'evaluation s'est bien passee
336 self.fichier_err = None
337 self.old_contexte_fichier_init=old_context
338 self.reevalue_sd_jdc()
340 def make_poursuite(self):
341 """ Cette methode est appelée par la fonction sd_prod de la macro POURSUITE
343 if not hasattr(self,'fichier_ini') :
344 # Si le fichier n'est pas defini on le demande
345 f,text=self.get_file(fic_origine=self.parent.nom)
346 # On memorise le fichier retourne
348 self.fichier_text = text
349 import Extensions.jdc_include
350 self.JdC_aux=Extensions.jdc_include.JdC_poursuite
351 self.contexte_fichier_init={}
353 self.fichier_err="Le fichier POURSUITE n'est pas defini"
355 self.fichier_err=None
357 if self.fichier_err is not None: raise Exception(self.fichier_err)
360 self.make_contexte_include(self.fichier_ini,self.fichier_text)
362 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
364 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier poursuite",
365 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
369 self.fichier_err = string.join(l)
370 self.contexte_fichier_init={}
374 # Si le fichier est deja defini on ne reevalue pas le fichier
375 # et on leve une exception si une erreur a été enregistrée
376 if self.fichier_err is not None: raise Exception(self.fichier_err)
379 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
380 def make_include(self,unite=None):
382 Inclut un fichier dont l'unite logique est unite
383 Cette methode est appelee par la fonction sd_prod de la macro INCLUDE
384 Si l'INCLUDE est invalide, la methode doit produire une exception
385 Sinon on retourne None. Les concepts produits par l'INCLUDE sont
386 pris en compte par le JDC parent lors du calcul du contexte (appel de ???)
389 # On supprime l'attribut unite qui bloque l'evaluation du source de l'INCLUDE
390 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
392 # Si unite n'a pas de valeur, l'etape est forcement invalide. On peut retourner None
393 if not unite : return
395 if not hasattr(self,'fichier_ini') :
396 # Si le fichier n'est pas defini on le demande
397 f,text=self.get_file(unite=unite,fic_origine=self.parent.nom)
398 # On memorise le fichier retourne
400 self.fichier_text = text
401 self.contexte_fichier_init={}
403 self.fichier_err="Le fichier INCLUDE n est pas defini"
405 self.fichier_err=None
406 import Extensions.jdc_include
407 self.JdC_aux=Extensions.jdc_include.JdC_include
409 if self.fichier_err is not None: raise Exception(self.fichier_err)
412 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
414 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
416 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
417 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
421 self.fichier_err = string.join(l)
422 self.contexte_fichier_init={}
426 # Si le fichier est deja defini on ne reevalue pas le fichier
427 # et on leve une exception si une erreur a été enregistrée
428 #self.reevalue_fichier_init()
429 if self.fichier_err is not None: raise Exception(self.fichier_err)
432 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
433 def make_contexte(self,fichier,text):
435 Cette méthode sert à créer un contexte pour INCLUDE_MATERIAU
436 en interprétant un texte source Python
437 Elle est appelee par la fonction sd_prd d'INCLUDE_MATERIAU
439 # On supprime l'attribut mat qui bloque l'evaluation du source de l'INCLUDE_MATERIAU
440 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
441 if hasattr(self,'mat'):del self.mat
442 self.fichier_ini =fichier
443 self.fichier_text=text
444 self.fichier_err=None
445 self.contexte_fichier_init={}
446 # On specifie la classe a utiliser pour le JDC auxiliaire
447 import Extensions.jdc_include
448 self.JdC_aux=Extensions.jdc_include.JdC_include
450 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
452 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
455 self.fichier_err = string.join(l)
456 self.contexte_fichier_init={}
459 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
460 def update_sdprod(self,cr='non'):
461 # Cette methode peut etre appelee dans EFICAS avec des mots cles de
462 # la commande modifies. Ceci peut conduire a la construction ou
463 # a la reconstruction d'etapes dans le cas d'INCLUDE ou d'INCLUDE_MATERIAU
464 # Il faut donc positionner le current_step avant l'appel
465 CONTEXT.unset_current_step()
466 CONTEXT.set_current_step(self)
467 valid=Validation.V_MACRO_ETAPE.MACRO_ETAPE.update_sdprod(self,cr=cr)
468 CONTEXT.unset_current_step()