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 # On ajoute egalement le concept produit dans le sds_dict du parent
114 # sans verification car on est sur (verification integrée) que le nommage est possible
115 self.g_context.clear()
116 for k,v in j_context.items():
117 if not context_ini.has_key(k) or context_ini[k] != v:
119 self.parent.sds_dict[k]=v
121 # On récupère les étapes internes (pour validation)
124 # ainsi que le contexte courant
125 self.current_context=j.current_context
126 self.index_etape_courante=j.index_etape_courante
128 # XXX j.supprime() ???
129 # On force le contexte (etape courante) à self
130 CONTEXT.unset_current_step()
131 CONTEXT.set_current_step(self)
135 def verif_contexte(self,context):
137 On verifie que le contexte context peut etre inséré dans le jeu
138 de commandes à la position de self
140 for nom_sd,sd in context.items():
141 if not isinstance(sd,ASSD):continue
142 if self.parent.get_sd_apres_etape(nom_sd,etape=self):
143 # Il existe un concept apres self => impossible d'inserer
144 raise Exception("Impossible d'inclure le fichier. Un concept de nom " +
145 "%s existe déjà dans le jeu de commandes." % nom_sd)
147 def reevalue_sd_jdc(self):
149 Avec la liste des SD qui ont été supprimées, propage la
150 disparition de ces SD dans toutes les étapes et descendants
152 l_sd_supp,l_sd_repl = self.diff_contextes()
154 self.parent.delete_concept_after_etape(self,sd)
155 for old_sd,sd in l_sd_repl:
156 self.parent.replace_concept_after_etape(self,old_sd,sd)
158 def diff_contextes(self):
160 Réalise la différence entre les 2 contextes
161 old_contexte_fichier_init et contexte_fichier_init
162 cad retourne la liste des sd qui ont disparu ou ne derivent pas de la meme classe
163 et des sd qui ont ete remplacees
165 if not hasattr(self,'old_contexte_fichier_init'):return [],[]
168 for old_key in self.old_contexte_fichier_init.keys():
169 if not self.contexte_fichier_init.has_key(old_key):
170 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
171 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
173 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
174 # Un concept de meme nom existe
175 old_class=self.old_contexte_fichier_init[old_key].__class__
176 if not isinstance(self.contexte_fichier_init[old_key],old_class):
177 # S'il n'est pas d'une classe derivee, on le supprime
178 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
180 l_sd_replaced.append((self.old_contexte_fichier_init[old_key],self.contexte_fichier_init[old_key]))
181 return l_sd_suppressed,l_sd_replaced
183 def control_sdprods(self,d):
185 Cette methode doit updater le contexte fournit par
186 l'appelant en argument (d) en fonction de sa definition
187 tout en verifiant que ses concepts produits ne sont pas
188 deja definis dans le contexte
190 if type(self.definition.op_init) == types.FunctionType:
191 apply(self.definition.op_init,(self,d))
193 if d.has_key(self.sd.nom):
194 # Le concept est deja defini
195 if self.reuse and self.reuse is d[self.sd.nom]:
196 # Le concept est reutilise : situation normale
199 # Redefinition du concept, on l'annule
200 #XXX on pourrait simplement annuler son nom pour conserver les objets
201 # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
202 self.sd=self.reuse=self.sdnom=None
205 # Le concept n'est pas defini, on peut updater d
206 d[self.sd.nom]=self.sd
207 # On verifie les concepts a droite du signe =
208 for co in self.sdprods:
209 if d.has_key(co.nom) and co is not d[co.nom] :
210 self.delete_concept(co)
215 def supprime_sdprods(self):
218 Lors d'une destruction d'etape, detruit tous les concepts produits
219 Un opérateur n a qu un concept produit
220 Une procedure n'en a aucun
221 Une macro en a en général plus d'un
223 if not self.is_reentrant() :
224 # l'étape n'est pas réentrante
225 # le concept retourné par l'étape est à supprimer car il était
228 self.parent.del_sdprod(self.sd)
229 self.parent.delete_concept(self.sd)
230 # On détruit les concepts à droite du signe =
231 for co in self.sdprods:
232 self.parent.del_sdprod(co)
233 self.parent.delete_concept(co)
234 # Si la macro a des etapes et des concepts inclus, on les detruit
235 for nom_sd,co in self.g_context.items():
236 if not isinstance(co,ASSD):continue
237 self.parent.del_sdprod(co)
238 self.parent.delete_concept(co)
239 # On met g_context à blanc
242 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
243 def Build_sd(self,nom):
245 Construit le concept produit de l'opérateur. Deux cas
246 peuvent se présenter :
248 - le parent n'est pas défini. Dans ce cas, l'étape prend en charge
249 la création et le nommage du concept.
251 - le parent est défini. Dans ce cas, l'étape demande au parent la
252 création et le nommage du concept.
255 if not self.isactif():return
256 # CCAR : meme modification que dans I_ETAPE
257 if not self.isvalid(sd='non') : return
260 # On positionne la macro self en tant que current_step pour que les
261 # étapes créées lors de l'appel à sd_prod et à op_init aient la macro
263 self.set_current_step()
265 sd= self.parent.create_sdprod(self,nom)
266 if type(self.definition.op_init) == types.FunctionType:
267 apply(self.definition.op_init,(self,self.parent.g_context))
269 sd=self.get_sd_prod()
270 if sd != None and self.reuse == None:
271 # On ne nomme le concept que dans le cas de non reutilisation
274 self.reset_current_step()
275 if self.jdc and self.jdc.par_lot == "NON" :
278 except AsException,e:
279 self.reset_current_step()
280 # Une erreur s'est produite lors de la construction du concept
281 # Comme on est dans EFICAS, on essaie de poursuivre quand meme
282 # Si on poursuit, on a le choix entre deux possibilités :
283 # 1. on annule la sd associée à self
284 # 2. on la conserve mais il faut qu'elle soit correcte et la retourner
285 # En plus il faut rendre coherents sdnom et sd.nom
286 # On choisit de retourner None et de mettre l'etape invalide
289 self.state="unchanged"
292 #raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
293 # 'fichier : ',self.appel[1],e)
297 self.reset_current_step()
298 l=traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2])
299 raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
300 'fichier : ',self.appel[1]+'\n',
303 def make_contexte_include(self,fichier,text):
305 Cette méthode sert à créer un contexte en interprétant un texte source
308 # on récupère le contexte d'un nouveau jdc dans lequel on interprete text
309 contexte = self.get_contexte_jdc(fichier,text)
310 if contexte == None :
311 raise Exception("Impossible de construire le jeu de commandes correspondant au fichier")
313 # Pour les macros de type include : INCLUDE, INCLUDE_MATERIAU et POURSUITE
314 # l'attribut g_context est un dictionnaire qui contient les concepts produits par inclusion
315 # l'attribut contexte_fichier_init est un dictionnaire qui contient les concepts produits
316 # en sortie de macro. g_context est obtenu en retirant de contexte_fichier_init les concepts
317 # existants en debut de macro contenus dans context_ini (dans get_contexte_jdc)
318 # g_context est utilisé pour avoir les concepts produits par la macro
319 # contexte_fichier_init est utilisé pour avoir les concepts supprimés par la macro
320 self.contexte_fichier_init = contexte
322 def reevalue_fichier_init(self):
323 """Recalcule les concepts produits par le fichier enregistre"""
324 old_context=self.contexte_fichier_init
326 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
328 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
329 self.fichier_err = string.join(l)
333 self.old_contexte_fichier_init=old_context
334 self.contexte_fichier_init={}
335 self.reevalue_sd_jdc()
338 # L'evaluation s'est bien passee
339 self.fichier_err = None
340 self.old_contexte_fichier_init=old_context
341 self.reevalue_sd_jdc()
343 def make_poursuite(self):
344 """ Cette methode est appelée par la fonction sd_prod de la macro POURSUITE
346 if not hasattr(self,'fichier_ini') :
347 # Si le fichier n'est pas defini on le demande
348 f,text=self.get_file(fic_origine=self.parent.nom)
349 # On memorise le fichier retourne
351 self.fichier_text = text
352 import Extensions.jdc_include
353 self.JdC_aux=Extensions.jdc_include.JdC_poursuite
354 self.contexte_fichier_init={}
356 self.fichier_err="Le fichier POURSUITE n'est pas defini"
358 self.fichier_err=None
360 if self.fichier_err is not None: raise Exception(self.fichier_err)
363 self.make_contexte_include(self.fichier_ini,self.fichier_text)
365 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
367 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier poursuite",
368 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
372 self.fichier_err = string.join(l)
373 self.contexte_fichier_init={}
377 # Si le fichier est deja defini on ne reevalue pas le fichier
378 # et on leve une exception si une erreur a été enregistrée
379 if self.fichier_err is not None: raise Exception(self.fichier_err)
382 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
383 def make_include(self,unite=None):
385 Inclut un fichier dont l'unite logique est unite
386 Cette methode est appelee par la fonction sd_prod de la macro INCLUDE
387 Si l'INCLUDE est invalide, la methode doit produire une exception
388 Sinon on retourne None. Les concepts produits par l'INCLUDE sont
389 pris en compte par le JDC parent lors du calcul du contexte (appel de ???)
392 # On supprime l'attribut unite qui bloque l'evaluation du source de l'INCLUDE
393 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
395 # Si unite n'a pas de valeur, l'etape est forcement invalide. On peut retourner None
396 if not unite : return
398 if not hasattr(self,'fichier_ini') :
399 # Si le fichier n'est pas defini on le demande
400 f,text=self.get_file(unite=unite,fic_origine=self.parent.nom)
401 # On memorise le fichier retourne
403 self.fichier_text = text
404 self.contexte_fichier_init={}
406 self.fichier_err="Le fichier INCLUDE n est pas defini"
408 self.fichier_err=None
409 import Extensions.jdc_include
410 self.JdC_aux=Extensions.jdc_include.JdC_include
412 if self.fichier_err is not None: raise Exception(self.fichier_err)
415 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
417 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
419 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
420 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
424 self.fichier_err = string.join(l)
425 self.contexte_fichier_init={}
429 # Si le fichier est deja defini on ne reevalue pas le fichier
430 # et on leve une exception si une erreur a été enregistrée
431 #self.reevalue_fichier_init()
432 if self.fichier_err is not None: raise Exception(self.fichier_err)
435 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
436 def make_contexte(self,fichier,text):
438 Cette méthode sert à créer un contexte pour INCLUDE_MATERIAU
439 en interprétant un texte source Python
440 Elle est appelee par la fonction sd_prd d'INCLUDE_MATERIAU
442 # On supprime l'attribut mat qui bloque l'evaluation du source de l'INCLUDE_MATERIAU
443 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
444 if hasattr(self,'mat'):del self.mat
445 self.fichier_ini =fichier
446 self.fichier_text=text
447 self.fichier_err=None
448 self.contexte_fichier_init={}
449 # On specifie la classe a utiliser pour le JDC auxiliaire
450 import Extensions.jdc_include
451 self.JdC_aux=Extensions.jdc_include.JdC_include
453 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
455 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
458 self.fichier_err = string.join(l)
459 self.contexte_fichier_init={}
462 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
463 def update_sdprod(self,cr='non'):
464 # Cette methode peut etre appelee dans EFICAS avec des mots cles de
465 # la commande modifies. Ceci peut conduire a la construction ou
466 # a la reconstruction d'etapes dans le cas d'INCLUDE ou d'INCLUDE_MATERIAU
467 # Il faut donc positionner le current_step avant l'appel
468 CONTEXT.unset_current_step()
469 CONTEXT.set_current_step(self)
470 valid=Validation.V_MACRO_ETAPE.MACRO_ETAPE.update_sdprod(self,cr=cr)
471 CONTEXT.unset_current_step()