1 # -*- coding: utf-8 -*-
2 # CONFIGURATION MANAGEMENT OF EDF VERSION
3 # ======================================================================
4 # COPYRIGHT (C) 1991 - 2002 EDF R&D WWW.CODE-ASTER.ORG
5 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
6 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
7 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
8 # (AT YOUR OPTION) ANY LATER VERSION.
10 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
11 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
12 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
13 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
15 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
16 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
17 # 1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
20 # ======================================================================
25 import traceback,types,string
29 from Noyau.N_ASSD import ASSD
31 # import rajoutés suite à l'ajout de Build_sd --> à résorber
32 import Noyau, Validation.V_MACRO_ETAPE
33 from Noyau import N_Exception
34 from Noyau.N_Exception import AsException
35 # fin import à résorber
37 class MACRO_ETAPE(I_ETAPE.ETAPE):
41 self.recorded_units={}
43 def get_sdprods(self,nom_sd):
45 Fonction : retourne le concept produit par l etape de nom nom_sd
46 s il existe sinon None
48 if self.sd and self.sd.nom == nom_sd :return self.sd
49 for co in self.sdprods:
50 if co.nom == nom_sd:return co
51 if type(self.definition.op_init) == types.FunctionType:
53 apply(self.definition.op_init,(self,d))
54 return d.get(nom_sd,None)
57 def get_contexte_jdc(self,fichier,text):
59 Interprète text comme un texte de jdc et retourne le
61 cad le dictionnaire des sd disponibles à la dernière étape
62 Si text n'est pas un texte de jdc valide, retourne None
64 --> utilisée par ops.POURSUITE et INCLUDE
67 # on essaie de créer un objet JDC auxiliaire avec un contexte initial
68 context_ini = self.parent.get_contexte_avant(self)
70 # Indispensable avant de creer un nouveau JDC
71 CONTEXT.unset_current_step()
74 if hasattr(self,'prefix'):
75 prefix_include=self.prefix
76 # ATTENTION : le dictionnaire recorded_units sert à memoriser les unites des
77 # fichiers inclus. Il est preferable de garder le meme dictionnaire pendant
78 # tout le traitement et de ne pas le reinitialiser brutalement (utiliser clear plutot)
79 # si on ne veut pas perdre la memoire des unites.
80 # En principe si la memorisation est faite au bon moment il n'est pas necessaire
81 # de prendre cette precaution mais ce n'est pas vrai partout.
82 old_recorded_units=self.recorded_units.copy()
83 self.recorded_units.clear()
85 j=self.JdC_aux( procedure=text,cata=self.jdc.cata,
87 context_ini = context_ini,
89 jdc_pere=self.jdc,etape_include=self,
90 prefix_include=prefix_include,
91 recorded_units=self.recorded_units,
92 old_recorded_units=old_recorded_units,**args)
95 # On récupère les étapes internes (pour validation)
99 # On force le contexte (etape courante) à self
100 CONTEXT.unset_current_step()
101 CONTEXT.set_current_step(self)
104 if not j.cr.estvide():
105 # Erreurs dans l'INCLUDE. On garde la memoire du fichier mais on n'insere pas les concepts
106 # On force le contexte (etape courante) à self
107 CONTEXT.unset_current_step()
108 CONTEXT.set_current_step(self)
109 raise Exception("Impossible de relire le fichier\n"+str(j.cr))
113 # On force le contexte (etape courante) à self
114 CONTEXT.unset_current_step()
115 CONTEXT.set_current_step(self)
116 raise Exception("Le fichier include contient des erreurs\n"+str(j.cr))
118 # On recupere le contexte apres la derniere etape
119 j_context=j.get_contexte_avant(None)
121 # Cette verification n'est plus necessaire elle est integree dans le JDC_INCLUDE
122 self.verif_contexte(j_context)
124 # On remplit le dictionnaire des concepts produits inclus
125 # en retirant les concepts présents dans le contexte initial
126 # On ajoute egalement le concept produit dans le sds_dict du parent
127 # sans verification car on est sur (verification integrée) que le nommage est possible
128 self.g_context.clear()
129 for k,v in j_context.items():
130 if not context_ini.has_key(k) or context_ini[k] != v:
132 self.parent.sds_dict[k]=v
135 # On recupere le contexte courant
136 self.current_context=j.current_context
137 self.index_etape_courante=j.index_etape_courante
139 # XXX j.supprime() ???
140 # On rétablit le contexte (etape courante) à self
141 CONTEXT.unset_current_step()
142 CONTEXT.set_current_step(self)
146 def verif_contexte(self,context):
148 On verifie que le contexte context peut etre inséré dans le jeu
149 de commandes à la position de self
151 for nom_sd,sd in context.items():
152 if not isinstance(sd,ASSD):continue
153 #if self.parent.get_sd_apres_etape(nom_sd,etape=self):
154 if self.parent.get_sd_apres_etape_avec_detruire(nom_sd,sd,etape=self):
155 # Il existe un concept produit par une etape apres self => impossible d'inserer
156 # On force le contexte (etape courante) à self
157 CONTEXT.unset_current_step()
158 CONTEXT.set_current_step(self)
159 raise Exception("Impossible d'inclure le fichier. Un concept de nom " +
160 "%s existe déjà dans le jeu de commandes." % nom_sd)
162 def reevalue_sd_jdc(self):
164 Avec la liste des SD qui ont été supprimées, propage la
165 disparition de ces SD dans toutes les étapes et descendants
167 l_sd_supp,l_sd_repl = self.diff_contextes()
169 self.parent.delete_concept_after_etape(self,sd)
170 for old_sd,sd in l_sd_repl:
171 self.parent.replace_concept_after_etape(self,old_sd,sd)
173 def diff_contextes(self):
175 Réalise la différence entre les 2 contextes
176 old_contexte_fichier_init et contexte_fichier_init
177 cad retourne la liste des sd qui ont disparu ou ne derivent pas de la meme classe
178 et des sd qui ont ete remplacees
180 if not hasattr(self,'old_contexte_fichier_init'):return [],[]
183 for old_key in self.old_contexte_fichier_init.keys():
184 if not self.contexte_fichier_init.has_key(old_key):
185 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
186 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
188 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
189 # Un concept de meme nom existe
190 old_class=self.old_contexte_fichier_init[old_key].__class__
191 if not isinstance(self.contexte_fichier_init[old_key],old_class):
192 # S'il n'est pas d'une classe derivee, on le supprime
193 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
195 l_sd_replaced.append((self.old_contexte_fichier_init[old_key],self.contexte_fichier_init[old_key]))
196 return l_sd_suppressed,l_sd_replaced
198 def control_sdprods(self,d):
200 Cette methode doit updater le contexte fournit par
201 l'appelant en argument (d) en fonction de sa definition
202 tout en verifiant que ses concepts produits ne sont pas
203 deja definis dans le contexte
205 if hasattr(self,"fichier_unite"):
206 self.update_fichier_init(self.fichier_unite)
209 if type(self.definition.op_init) == types.FunctionType:
210 apply(self.definition.op_init,(self,d))
212 if d.has_key(self.sd.nom):
213 # Le concept est deja defini
214 if self.reuse and self.reuse is d[self.sd.nom]:
215 # Le concept est reutilise : situation normale
218 # Redefinition du concept, on l'annule
219 #XXX on pourrait simplement annuler son nom pour conserver les objets
220 # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
221 self.sd=self.reuse=self.sdnom=None
224 # Le concept n'est pas defini, on peut updater d
225 d[self.sd.nom]=self.sd
226 # On verifie les concepts a droite du signe =
227 for co in self.sdprods:
228 if d.has_key(co.nom) and co is not d[co.nom] :
229 self.delete_concept(co)
234 def supprime_sdprods(self):
237 Lors d'une destruction d'etape, detruit tous les concepts produits
238 Un opérateur n a qu un concept produit
239 Une procedure n'en a aucun
240 Une macro en a en général plus d'un
242 if not self.is_reentrant() :
243 # l'étape n'est pas réentrante
244 # le concept retourné par l'étape est à supprimer car il était
247 self.parent.del_sdprod(self.sd)
248 self.parent.delete_concept(self.sd)
249 # On détruit les concepts à droite du signe =
250 for co in self.sdprods:
251 self.parent.del_sdprod(co)
252 self.parent.delete_concept(co)
253 # Si la macro a des etapes et des concepts inclus, on les detruit
254 for nom_sd,co in self.g_context.items():
255 if not isinstance(co,ASSD):continue
256 self.parent.del_sdprod(co)
257 self.parent.delete_concept(co)
258 # On met g_context à blanc
261 def make_contexte_include(self,fichier,text):
263 Cette méthode sert à créer un contexte en interprétant un texte source
266 # on récupère le contexte d'un nouveau jdc dans lequel on interprete text
267 contexte = self.get_contexte_jdc(fichier,text)
268 if contexte == None :
269 raise Exception("Impossible de construire le jeu de commandes correspondant au fichier")
271 # Pour les macros de type include : INCLUDE, INCLUDE_MATERIAU et POURSUITE
272 # l'attribut g_context est un dictionnaire qui contient les concepts produits par inclusion
273 # l'attribut contexte_fichier_init est un dictionnaire qui contient les concepts produits
274 # en sortie de macro. g_context est obtenu en retirant de contexte_fichier_init les concepts
275 # existants en debut de macro contenus dans context_ini (dans get_contexte_jdc)
276 # g_context est utilisé pour avoir les concepts produits par la macro
277 # contexte_fichier_init est utilisé pour avoir les concepts supprimés par la macro
278 self.contexte_fichier_init = contexte
280 def reevalue_fichier_init(self):
281 """Recalcule les concepts produits par le fichier enregistre"""
282 old_context=self.contexte_fichier_init
284 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
286 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
287 self.fichier_err = string.join(l)
291 self.old_contexte_fichier_init=old_context
292 self.contexte_fichier_init={}
293 self.reevalue_sd_jdc()
296 # L'evaluation s'est bien passee
297 self.fichier_err = None
298 self.old_contexte_fichier_init=old_context
299 self.reevalue_sd_jdc()
301 def update_fichier_init(self,unite):
302 """Reevalue le fichier init sans demander (dans la mesure du possible) a l'utilisateur
303 les noms des fichiers
304 Ceci suppose que les relations entre unites et noms ont été memorisees préalablement
307 self.fichier_err=None
308 self.old_contexte_fichier_init=self.contexte_fichier_init
310 if unite != self.fichier_unite or not self.parent.recorded_units.has_key(unite):
311 # Changement d'unite ou Nouvelle unite
312 f,text=self.get_file(unite=unite,fic_origine=self.parent.nom)
316 self.fichier_text=text
317 self.recorded_units=units
318 if self.fichier_ini is None and self.jdc.appli:
319 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
320 message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
322 # Meme unite existante
323 f,text,units=self.parent.recorded_units[unite]
325 self.fichier_text=text
326 self.recorded_units=units
328 if self.fichier_ini is None:
329 # Le fichier n'est pas défini
330 self.fichier_err="Le fichier associé n'est pas défini"
331 self.parent.change_unit(unite,self,self.fichier_unite)
333 self.contexte_fichier_init={}
334 self.parent.reset_context()
335 self.reevalue_sd_jdc()
339 self.make_contexte_include(self.fichier_ini,self.fichier_text)
340 # Les 3 attributs fichier_ini fichier_text recorded_units doivent etre corrects
341 # avant d'appeler change_unit
342 self.parent.change_unit(unite,self,self.fichier_unite)
344 # Erreurs lors de l'evaluation de text dans un JDC auxiliaire
345 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
346 # On conserve la memoire du nouveau fichier
347 # mais on n'utilise pas les concepts crees par ce fichier
348 # on met l'etape en erreur : fichier_err=string.join(l)
349 self.fichier_err=string.join(l)
350 self.parent.change_unit(unite,self,self.fichier_unite)
352 self.contexte_fichier_init={}
354 # Le contexte du parent doit etre reinitialise car les concepts produits ont changé
355 self.parent.reset_context()
356 # Si des concepts ont disparu lors du changement de fichier, on demande leur suppression
357 self.reevalue_sd_jdc()
359 def record_unite(self):
360 if self.nom == "POURSUITE":
361 self.parent.record_unit(None,self)
363 if hasattr(self,'fichier_unite') :
364 self.parent.record_unit(self.fichier_unite,self)
366 def get_file_memo(self,unite=None,fic_origine=''):
367 """Retourne le nom du fichier et le source correspondant a l'unite unite
368 Initialise en plus recorded_units
371 if self.parent.old_recorded_units.has_key(unite):
372 f,text,units=self.parent.old_recorded_units[unite]
373 self.recorded_units=units
376 f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
379 self.recorded_units=units
380 if f is None and self.jdc.appli:
381 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
382 message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
385 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
386 def get_file(self,unite=None,fic_origine=''):
387 """Retourne le nom du fichier et le source correspondant a l'unite unite
388 Initialise en plus recorded_units
392 f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
395 self.recorded_units=units
398 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
399 def make_include(self,unite=None):
401 Inclut un fichier dont l'unite logique est unite
402 Cette methode est appelee par la fonction sd_prod de la macro INCLUDE
403 Si l'INCLUDE est invalide, la methode doit produire une exception
404 Sinon on retourne None. Les concepts produits par l'INCLUDE sont
405 pris en compte par le JDC parent lors du calcul du contexte (appel de ???)
408 # On supprime l'attribut unite qui bloque l'evaluation du source de l'INCLUDE
409 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
411 # Si unite n'a pas de valeur, l'etape est forcement invalide. On peut retourner None
412 if not unite : return
414 if not hasattr(self,'fichier_ini') :
415 # Si le fichier n'est pas defini on le demande
416 f,text=self.get_file_memo(unite=unite,fic_origine=self.parent.nom)
417 # On memorise le fichier retourne
419 self.fichier_text = text
420 self.contexte_fichier_init={}
421 self.fichier_unite=unite
422 self.fichier_err=None
423 import Extensions.jdc_include
424 self.JdC_aux=Extensions.jdc_include.JdC_include
427 self.fichier_err="Le fichier INCLUDE n est pas defini"
428 self.parent.record_unit(unite,self)
429 raise Exception(self.fichier_err)
432 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
433 self.parent.record_unit(unite,self)
435 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
437 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
438 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
440 self.parent.record_unit(unite,self)
442 self.fichier_err = string.join(l)
443 self.contexte_fichier_init={}
447 # Si le fichier est deja defini on ne reevalue pas le fichier
448 # et on leve une exception si une erreur a été enregistrée
449 self.update_fichier_init(unite)
450 self.fichier_unite=unite
451 if self.fichier_err is not None: raise Exception(self.fichier_err)
454 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
455 def make_contexte(self,fichier,text):
457 Cette méthode sert à créer un contexte pour INCLUDE_MATERIAU
458 en interprétant un texte source Python
459 Elle est appelee par la fonction sd_prd d'INCLUDE_MATERIAU
461 # On supprime l'attribut mat qui bloque l'evaluation du source de l'INCLUDE_MATERIAU
462 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
463 if hasattr(self,'mat'):del self.mat
464 self.fichier_ini =fichier
465 self.fichier_unite =fichier
466 self.fichier_text=text
467 self.fichier_err=None
468 self.contexte_fichier_init={}
469 # On specifie la classe a utiliser pour le JDC auxiliaire
470 import Extensions.jdc_include
471 self.JdC_aux=Extensions.jdc_include.JdC_include
473 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
474 self.parent.record_unit(self.fichier_unite,self)
476 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
477 self.fichier_err = string.join(l)
478 self.parent.record_unit(self.fichier_unite,self)
480 self.contexte_fichier_init={}
483 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
484 def update_sdprod(self,cr='non'):
485 # Cette methode peut etre appelee dans EFICAS avec des mots cles de
486 # la commande modifies. Ceci peut conduire a la construction ou
487 # a la reconstruction d'etapes dans le cas d'INCLUDE ou d'INCLUDE_MATERIAU
488 # Il faut donc positionner le current_step avant l'appel
489 CONTEXT.unset_current_step()
490 CONTEXT.set_current_step(self)
491 valid=Validation.V_MACRO_ETAPE.MACRO_ETAPE.update_sdprod(self,cr=cr)
492 CONTEXT.unset_current_step()
495 #ATTENTION SURCHARGE: cette methode surcharge celle de Noyau a garder en synchro
496 def Build_sd(self,nom):
498 Methode de Noyau surchargee pour poursuivre malgre tout
499 si une erreur se produit pendant la creation du concept produit
502 sd=Noyau.N_MACRO_ETAPE.MACRO_ETAPE.Build_sd(self,nom)
503 self.state="modified"
504 except AsException,e:
505 # Une erreur s'est produite lors de la construction du concept
506 # Comme on est dans EFICAS, on essaie de poursuivre quand meme
507 # Si on poursuit, on a le choix entre deux possibilités :
508 # 1. on annule la sd associée à self
509 # 2. on la conserve mais il faut la retourner
510 # On choisit de l'annuler
511 # En plus il faut rendre coherents sdnom et sd.nom
514 self.state="unchanged"
519 #ATTENTION SURCHARGE: cette methode surcharge celle de Noyau a garder en synchro
520 def make_poursuite(self):
521 """ Cette methode est appelée par la fonction sd_prod de la macro POURSUITE
523 if not hasattr(self,'fichier_ini') :
524 # Si le fichier n'est pas defini on le demande
525 f,text=self.get_file_memo(fic_origine=self.parent.nom)
526 # On memorise le fichier retourne
528 self.fichier_unite = None
529 self.fichier_text = text
530 self.fichier_err=None
531 import Extensions.jdc_include
532 self.JdC_aux=Extensions.jdc_include.JdC_poursuite
533 self.contexte_fichier_init={}
536 self.fichier_err="Le fichier POURSUITE n'est pas defini"
537 self.parent.record_unit(None,self)
538 raise Exception(self.fichier_err)
541 self.make_contexte_include(self.fichier_ini,self.fichier_text)
542 self.parent.record_unit(None,self)
544 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
546 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier poursuite",
547 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
549 self.parent.record_unit(None,self)
551 self.fichier_err = string.join(l)
552 self.contexte_fichier_init={}
556 # Si le fichier est deja defini on ne reevalue pas le fichier
557 # et on leve une exception si une erreur a été enregistrée
558 self.update_fichier_init(None)
559 if self.fichier_err is not None: raise Exception(self.fichier_err)