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):
40 self.recorded_units={}
42 def get_sdprods(self,nom_sd):
44 Fonction : retourne le concept produit par l etape de nom nom_sd
45 s il existe sinon None
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:
52 apply(self.definition.op_init,(self,d))
53 return d.get(nom_sd,None)
56 def get_contexte_jdc(self,fichier,text):
58 Interprète text comme un texte de jdc et retourne le
60 cad le dictionnaire des sd disponibles à la dernière étape
61 Si text n'est pas un texte de jdc valide, retourne None
63 --> utilisée par ops.POURSUITE et INCLUDE
66 # on essaie de créer un objet JDC auxiliaire avec un contexte initial
67 context_ini = self.parent.get_contexte_avant(self)
69 # Indispensable avant de creer un nouveau JDC
70 CONTEXT.unset_current_step()
73 if hasattr(self,'prefix'):
74 prefix_include=self.prefix
76 j=self.JdC_aux( procedure=text,cata=self.jdc.cata,
78 context_ini = context_ini,
80 jdc_pere=self.jdc,etape_include=self,
81 prefix_include=prefix_include,
82 recorded_units=self.recorded_units,**args)
85 # On récupère les étapes internes (pour validation)
89 # On force le contexte (etape courante) à self
90 CONTEXT.unset_current_step()
91 CONTEXT.set_current_step(self)
94 if not j.cr.estvide():
95 # Erreurs dans l'INCLUDE. On garde la memoire du fichier mais on n'insere pas les concepts
96 # On force le contexte (etape courante) à self
97 CONTEXT.unset_current_step()
98 CONTEXT.set_current_step(self)
99 raise Exception("Impossible de relire le fichier\n"+str(j.cr))
103 # On force le contexte (etape courante) à self
104 CONTEXT.unset_current_step()
105 CONTEXT.set_current_step(self)
106 raise Exception("Le fichier include contient des erreurs\n"+str(j.cr))
108 # On recupere le contexte apres la derniere etape
109 j_context=j.get_contexte_avant(None)
111 # Cette verification n'est plus necessaire elle est integree dans le JDC_INCLUDE
112 self.verif_contexte(j_context)
114 # On remplit le dictionnaire des concepts produits inclus
115 # en retirant les concepts présents dans le contexte initial
116 # On ajoute egalement le concept produit dans le sds_dict du parent
117 # sans verification car on est sur (verification integrée) que le nommage est possible
118 self.g_context.clear()
119 for k,v in j_context.items():
120 if not context_ini.has_key(k) or context_ini[k] != v:
122 self.parent.sds_dict[k]=v
125 # On recupere le contexte courant
126 self.current_context=j.current_context
127 self.index_etape_courante=j.index_etape_courante
129 # XXX j.supprime() ???
130 # On rétablit le contexte (etape courante) à self
131 CONTEXT.unset_current_step()
132 CONTEXT.set_current_step(self)
136 def verif_contexte(self,context):
138 On verifie que le contexte context peut etre inséré dans le jeu
139 de commandes à la position de self
141 for nom_sd,sd in context.items():
142 if not isinstance(sd,ASSD):continue
143 if self.parent.get_sd_apres_etape(nom_sd,etape=self):
144 # Il existe un concept apres self => impossible d'inserer
145 # On force le contexte (etape courante) à self
146 CONTEXT.unset_current_step()
147 CONTEXT.set_current_step(self)
148 raise Exception("Impossible d'inclure le fichier. Un concept de nom " +
149 "%s existe déjà dans le jeu de commandes." % nom_sd)
151 def reevalue_sd_jdc(self):
153 Avec la liste des SD qui ont été supprimées, propage la
154 disparition de ces SD dans toutes les étapes et descendants
156 l_sd_supp,l_sd_repl = self.diff_contextes()
158 self.parent.delete_concept_after_etape(self,sd)
159 for old_sd,sd in l_sd_repl:
160 self.parent.replace_concept_after_etape(self,old_sd,sd)
162 def diff_contextes(self):
164 Réalise la différence entre les 2 contextes
165 old_contexte_fichier_init et contexte_fichier_init
166 cad retourne la liste des sd qui ont disparu ou ne derivent pas de la meme classe
167 et des sd qui ont ete remplacees
169 if not hasattr(self,'old_contexte_fichier_init'):return [],[]
172 for old_key in self.old_contexte_fichier_init.keys():
173 if not self.contexte_fichier_init.has_key(old_key):
174 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
175 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
177 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
178 # Un concept de meme nom existe
179 old_class=self.old_contexte_fichier_init[old_key].__class__
180 if not isinstance(self.contexte_fichier_init[old_key],old_class):
181 # S'il n'est pas d'une classe derivee, on le supprime
182 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
184 l_sd_replaced.append((self.old_contexte_fichier_init[old_key],self.contexte_fichier_init[old_key]))
185 return l_sd_suppressed,l_sd_replaced
187 def control_sdprods(self,d):
189 Cette methode doit updater le contexte fournit par
190 l'appelant en argument (d) en fonction de sa definition
191 tout en verifiant que ses concepts produits ne sont pas
192 deja definis dans le contexte
194 if hasattr(self,"fichier_unite"):
195 self.update_fichier_init(self.fichier_unite)
198 if type(self.definition.op_init) == types.FunctionType:
199 apply(self.definition.op_init,(self,d))
201 if d.has_key(self.sd.nom):
202 # Le concept est deja defini
203 if self.reuse and self.reuse is d[self.sd.nom]:
204 # Le concept est reutilise : situation normale
207 # Redefinition du concept, on l'annule
208 #XXX on pourrait simplement annuler son nom pour conserver les objets
209 # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
210 self.sd=self.reuse=self.sdnom=None
213 # Le concept n'est pas defini, on peut updater d
214 d[self.sd.nom]=self.sd
215 # On verifie les concepts a droite du signe =
216 for co in self.sdprods:
217 if d.has_key(co.nom) and co is not d[co.nom] :
218 self.delete_concept(co)
223 def supprime_sdprods(self):
226 Lors d'une destruction d'etape, detruit tous les concepts produits
227 Un opérateur n a qu un concept produit
228 Une procedure n'en a aucun
229 Une macro en a en général plus d'un
231 if not self.is_reentrant() :
232 # l'étape n'est pas réentrante
233 # le concept retourné par l'étape est à supprimer car il était
236 self.parent.del_sdprod(self.sd)
237 self.parent.delete_concept(self.sd)
238 # On détruit les concepts à droite du signe =
239 for co in self.sdprods:
240 self.parent.del_sdprod(co)
241 self.parent.delete_concept(co)
242 # Si la macro a des etapes et des concepts inclus, on les detruit
243 for nom_sd,co in self.g_context.items():
244 if not isinstance(co,ASSD):continue
245 self.parent.del_sdprod(co)
246 self.parent.delete_concept(co)
247 # On met g_context à blanc
250 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
251 def Build_sd(self,nom):
253 Construit le concept produit de l'opérateur. Deux cas
254 peuvent se présenter :
256 - le parent n'est pas défini. Dans ce cas, l'étape prend en charge
257 la création et le nommage du concept.
259 - le parent est défini. Dans ce cas, l'étape demande au parent la
260 création et le nommage du concept.
263 if not self.isactif():return
264 # CCAR : meme modification que dans I_ETAPE
265 if not self.isvalid(sd='non') : return
268 # On positionne la macro self en tant que current_step pour que les
269 # étapes créées lors de l'appel à sd_prod et à op_init aient la macro
271 self.set_current_step()
273 sd= self.parent.create_sdprod(self,nom)
274 if type(self.definition.op_init) == types.FunctionType:
275 apply(self.definition.op_init,(self,self.parent.g_context))
277 sd=self.get_sd_prod()
278 if sd != None and self.reuse == None:
279 # On ne nomme le concept que dans le cas de non reutilisation
282 self.reset_current_step()
283 # Si on est arrive ici, l'etape est valide
284 self.state="unchanged"
286 if self.jdc and self.jdc.par_lot == "NON" :
289 except AsException,e:
290 self.reset_current_step()
291 # Une erreur s'est produite lors de la construction du concept
292 # Comme on est dans EFICAS, on essaie de poursuivre quand meme
293 # Si on poursuit, on a le choix entre deux possibilités :
294 # 1. on annule la sd associée à self
295 # 2. on la conserve mais il faut qu'elle soit correcte et la retourner
296 # En plus il faut rendre coherents sdnom et sd.nom
297 # On choisit de retourner None et de mettre l'etape invalide
300 self.state="unchanged"
303 #raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
304 # 'fichier : ',self.appel[1],e)
308 self.reset_current_step()
309 l=traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2])
310 raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
311 'fichier : ',self.appel[1]+'\n',
314 def make_contexte_include(self,fichier,text):
316 Cette méthode sert à créer un contexte en interprétant un texte source
319 # on récupère le contexte d'un nouveau jdc dans lequel on interprete text
320 contexte = self.get_contexte_jdc(fichier,text)
321 if contexte == None :
322 raise Exception("Impossible de construire le jeu de commandes correspondant au fichier")
324 # Pour les macros de type include : INCLUDE, INCLUDE_MATERIAU et POURSUITE
325 # l'attribut g_context est un dictionnaire qui contient les concepts produits par inclusion
326 # l'attribut contexte_fichier_init est un dictionnaire qui contient les concepts produits
327 # en sortie de macro. g_context est obtenu en retirant de contexte_fichier_init les concepts
328 # existants en debut de macro contenus dans context_ini (dans get_contexte_jdc)
329 # g_context est utilisé pour avoir les concepts produits par la macro
330 # contexte_fichier_init est utilisé pour avoir les concepts supprimés par la macro
331 self.contexte_fichier_init = contexte
333 def reevalue_fichier_init(self):
334 """Recalcule les concepts produits par le fichier enregistre"""
335 old_context=self.contexte_fichier_init
337 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
339 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
340 self.fichier_err = string.join(l)
344 self.old_contexte_fichier_init=old_context
345 self.contexte_fichier_init={}
346 self.reevalue_sd_jdc()
349 # L'evaluation s'est bien passee
350 self.fichier_err = None
351 self.old_contexte_fichier_init=old_context
352 self.reevalue_sd_jdc()
354 def update_fichier_init(self,unite):
355 """Reevalue le fichier init sans demander (dans la mesure du possible) a l'utilisateur
356 les noms des fichiers
357 Ceci suppose que les relations entre unites et noms ont été memorisees préalablement
359 if self.parent.recorded_units.has_key(unite):
360 f,text,units=self.parent.recorded_units[unite]
362 f,text=self.get_file(unite=unite,fic_origine=self.parent.nom)
365 self.fichier_text=text
366 self.fichier_err=None
367 self.recorded_units=units
368 self.old_contexte_fichier_init=self.contexte_fichier_init
371 self.make_contexte_include(f,text)
373 # Erreurs lors de l'evaluation de text dans un JDC auxiliaire
374 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
375 # On conserve la memoire du nouveau fichier
376 # mais on n'utilise pas les concepts crees par ce fichier
377 # on met l'etape en erreur : fichier_err=string.join(l)
378 self.fichier_err=string.join(l)
380 self.contexte_fichier_init={}
382 # Le contexte du parent doit etre reinitialise car les concepts produits ont changé
383 self.parent.reset_context()
384 # Si des concepts ont disparu lors du changement de fichier, on demande leur suppression
385 self.reevalue_sd_jdc()
387 def record_unite(self):
388 if self.nom == "POURSUITE":
389 self.parent.record_unit(None,self)
391 if hasattr(self,'fichier_unite') :
392 self.parent.record_unit(self.fichier_unite,self)
394 def make_poursuite(self):
395 """ Cette methode est appelée par la fonction sd_prod de la macro POURSUITE
397 if not hasattr(self,'fichier_ini') :
398 # Si le fichier n'est pas defini on le demande
399 f,text=self.get_file(fic_origine=self.parent.nom)
400 # On memorise le fichier retourne
402 self.fichier_unite = None
403 self.fichier_text = text
404 import Extensions.jdc_include
405 self.JdC_aux=Extensions.jdc_include.JdC_poursuite
406 self.contexte_fichier_init={}
407 self.parent.record_unit(None,self)
409 self.fichier_err="Le fichier POURSUITE n'est pas defini"
411 self.fichier_err=None
413 if self.fichier_err is not None: raise Exception(self.fichier_err)
416 self.make_contexte_include(self.fichier_ini,self.fichier_text)
418 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
420 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier poursuite",
421 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
425 self.fichier_err = string.join(l)
426 self.contexte_fichier_init={}
430 # Si le fichier est deja defini on ne reevalue pas le fichier
431 # et on leve une exception si une erreur a été enregistrée
432 self.update_fichier_init(None)
433 if self.fichier_err is not None: raise Exception(self.fichier_err)
435 def get_file(self,unite=None,fic_origine=''):
437 Retourne le nom du fichier associe a l unite logique unite (entier)
438 ainsi que le source contenu dans le fichier
439 Retourne en plus un dictionnaire contenant les sous includes memorises
442 if self.parent.recorded_units.has_key(unite):
443 f,text,units=self.parent.recorded_units[unite]
445 f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
448 self.recorded_units=units
451 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
452 def make_include(self,unite=None):
454 Inclut un fichier dont l'unite logique est unite
455 Cette methode est appelee par la fonction sd_prod de la macro INCLUDE
456 Si l'INCLUDE est invalide, la methode doit produire une exception
457 Sinon on retourne None. Les concepts produits par l'INCLUDE sont
458 pris en compte par le JDC parent lors du calcul du contexte (appel de ???)
461 # On supprime l'attribut unite qui bloque l'evaluation du source de l'INCLUDE
462 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
464 # Si unite n'a pas de valeur, l'etape est forcement invalide. On peut retourner None
465 if not unite : return
466 self.fichier_unite=unite
468 if not hasattr(self,'fichier_ini') :
469 # Si le fichier n'est pas defini on le demande
470 f,text=self.get_file(unite=unite,fic_origine=self.parent.nom)
471 # On memorise le fichier retourne
473 self.fichier_text = text
474 self.contexte_fichier_init={}
475 self.parent.record_unit(unite,self)
477 self.fichier_err="Le fichier INCLUDE n est pas defini"
479 self.fichier_err=None
480 import Extensions.jdc_include
481 self.JdC_aux=Extensions.jdc_include.JdC_include
483 if self.fichier_err is not None: raise Exception(self.fichier_err)
486 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
488 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
490 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
491 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
495 self.fichier_err = string.join(l)
496 self.contexte_fichier_init={}
500 # Si le fichier est deja defini on ne reevalue pas le fichier
501 # et on leve une exception si une erreur a été enregistrée
502 self.update_fichier_init(unite)
503 if self.fichier_err is not None: raise Exception(self.fichier_err)
506 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
507 def make_contexte(self,fichier,text):
509 Cette méthode sert à créer un contexte pour INCLUDE_MATERIAU
510 en interprétant un texte source Python
511 Elle est appelee par la fonction sd_prd d'INCLUDE_MATERIAU
513 # On supprime l'attribut mat qui bloque l'evaluation du source de l'INCLUDE_MATERIAU
514 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
515 if hasattr(self,'mat'):del self.mat
516 self.fichier_ini =fichier
517 self.fichier_unite =fichier
518 self.fichier_text=text
519 self.parent.record_unit(self.fichier_unite,self)
520 self.fichier_err=None
521 self.contexte_fichier_init={}
522 # On specifie la classe a utiliser pour le JDC auxiliaire
523 import Extensions.jdc_include
524 self.JdC_aux=Extensions.jdc_include.JdC_include
526 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
528 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
531 self.fichier_err = string.join(l)
532 self.contexte_fichier_init={}
535 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
536 def update_sdprod(self,cr='non'):
537 # Cette methode peut etre appelee dans EFICAS avec des mots cles de
538 # la commande modifies. Ceci peut conduire a la construction ou
539 # a la reconstruction d'etapes dans le cas d'INCLUDE ou d'INCLUDE_MATERIAU
540 # Il faut donc positionner le current_step avant l'appel
541 CONTEXT.unset_current_step()
542 CONTEXT.set_current_step(self)
543 valid=Validation.V_MACRO_ETAPE.MACRO_ETAPE.update_sdprod(self,cr=cr)
544 CONTEXT.unset_current_step()