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
66 #print "get_contexte_jdc"
68 # on essaie de créer un objet JDC auxiliaire avec un contexte initial
69 context_ini = self.parent.get_contexte_avant(self)
71 # Indispensable avant de creer un nouveau JDC
72 CONTEXT.unset_current_step()
75 if hasattr(self,'prefix'):
76 prefix_include=self.prefix
77 # ATTENTION : le dictionnaire recorded_units sert à memoriser les unites des
78 # fichiers inclus. Il est preferable de garder le meme dictionnaire pendant
79 # tout le traitement et de ne pas le reinitialiser brutalement (utiliser
80 # clear plutot) si on ne veut pas perdre la memoire des unites.
81 # En principe si la memorisation est faite au bon moment il n'est pas necessaire
82 # de prendre cette precaution mais ce n'est pas vrai partout.
83 old_recorded_units=self.recorded_units.copy()
84 #print "get_contexte_jdc",id(self.recorded_units)
85 #self.recorded_units.clear()
87 j=self.JdC_aux( procedure=text, nom=fichier,
90 cata_ord_dico=self.jdc.cata_ordonne_dico,
91 context_ini = context_ini,
92 jdc_pere=self.jdc,etape_include=self,
93 prefix_include=prefix_include,
94 recorded_units=self.recorded_units,
95 old_recorded_units=old_recorded_units,**args)
98 # On récupère les étapes internes (pour validation)
101 traceback.print_exc()
102 # On force le contexte (etape courante) à self
103 CONTEXT.unset_current_step()
104 CONTEXT.set_current_step(self)
107 if not j.cr.estvide():
108 # Erreurs dans l'INCLUDE. On garde la memoire du fichier
109 # mais on n'insere pas les concepts
110 # On force le contexte (etape courante) à self
111 CONTEXT.unset_current_step()
112 CONTEXT.set_current_step(self)
113 raise Exception("Impossible de relire le fichier\n"+str(j.cr))
116 # L'INCLUDE n'est pas valide.
117 # on produit un rapport d'erreurs
118 # On force le contexte (etape courante) à self
120 CONTEXT.unset_current_step()
121 CONTEXT.set_current_step(self)
122 raise Exception("Le fichier include contient des erreurs\n"+str(cr))
124 # Si aucune erreur rencontrée
125 # On recupere le contexte de l'include verifie
127 j_context=j.get_verif_contexte()
129 CONTEXT.unset_current_step()
130 CONTEXT.set_current_step(self)
133 # On remplit le dictionnaire des concepts produits inclus
134 # en retirant les concepts présents dans le contexte initial
135 # On ajoute egalement le concept produit dans le sds_dict du parent
136 # sans verification car on est sur (verification integrée) que
137 # le nommage est possible
138 self.g_context.clear()
139 for k,v in j_context.items():
140 if not context_ini.has_key(k) or context_ini[k] != v:
142 self.parent.sds_dict[k]=v
145 # On recupere le contexte courant
146 self.current_context=j.current_context
147 self.index_etape_courante=j.index_etape_courante
150 # XXX j.supprime() ???
151 # On rétablit le contexte (etape courante) à self
152 CONTEXT.unset_current_step()
153 CONTEXT.set_current_step(self)
157 def reevalue_sd_jdc(self):
159 Avec la liste des SD qui ont été supprimées, propage la
160 disparition de ces SD dans toutes les étapes et descendants
162 l_sd_supp,l_sd_repl = self.diff_contextes()
164 self.parent.delete_concept_after_etape(self,sd)
165 for old_sd,sd in l_sd_repl:
166 self.parent.replace_concept_after_etape(self,old_sd,sd)
168 def diff_contextes(self):
170 Réalise la différence entre les 2 contextes
171 old_contexte_fichier_init et contexte_fichier_init
172 cad retourne la liste des sd qui ont disparu ou ne derivent pas
173 de la meme classe et des sd qui ont ete remplacees
175 if not hasattr(self,'old_contexte_fichier_init'):return [],[]
178 for old_key in self.old_contexte_fichier_init.keys():
179 if not self.contexte_fichier_init.has_key(old_key):
180 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
181 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
183 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
184 # Un concept de meme nom existe
185 old_class=self.old_contexte_fichier_init[old_key].__class__
186 if not isinstance(self.contexte_fichier_init[old_key],old_class):
187 # S'il n'est pas d'une classe derivee, on le supprime
188 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
190 l_sd_replaced.append((self.old_contexte_fichier_init[old_key],self.contexte_fichier_init[old_key]))
191 return l_sd_suppressed,l_sd_replaced
193 def control_sdprods(self,d):
195 Cette methode doit updater le contexte fournit par
196 l'appelant en argument (d) en fonction de sa definition
197 tout en verifiant que ses concepts produits ne sont pas
198 deja definis dans le contexte
200 if hasattr(self,"fichier_unite"):
201 self.update_fichier_init(self.fichier_unite)
204 if type(self.definition.op_init) == types.FunctionType:
205 apply(self.definition.op_init,(self,d))
207 if d.has_key(self.sd.nom):
208 # Le concept est deja defini
209 if self.reuse and self.reuse is d[self.sd.nom]:
210 # Le concept est reutilise : situation normale
213 # Redefinition du concept, on l'annule
214 #XXX on pourrait simplement annuler son nom pour conserver les objets
215 # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
216 self.sd=self.reuse=self.sdnom=None
219 # Le concept n'est pas defini, on peut updater d
220 d[self.sd.nom]=self.sd
221 # On verifie les concepts a droite du signe =
222 for co in self.sdprods:
223 if d.has_key(co.nom) and co is not d[co.nom] :
224 self.delete_concept(co)
229 def supprime_sdprods(self):
232 Lors d'une destruction d'etape, detruit tous les concepts produits
233 Un opérateur n a qu un concept produit
234 Une procedure n'en a aucun
235 Une macro en a en général plus d'un
237 if not self.is_reentrant() :
238 # l'étape n'est pas réentrante
239 # le concept retourné par l'étape est à supprimer car il était
242 self.parent.del_sdprod(self.sd)
243 self.parent.delete_concept(self.sd)
244 # On détruit les concepts à droite du signe =
245 for co in self.sdprods:
246 self.parent.del_sdprod(co)
247 self.parent.delete_concept(co)
248 # Si la macro a des etapes et des concepts inclus, on les detruit
249 for nom_sd,co in self.g_context.items():
250 if not isinstance(co,ASSD):continue
251 self.parent.del_sdprod(co)
252 self.parent.delete_concept(co)
253 # On met g_context à blanc
256 def make_contexte_include(self,fichier,text):
258 Cette méthode sert à créer un contexte en interprétant un texte source
261 #print "make_contexte_include"
262 # on récupère le contexte d'un nouveau jdc dans lequel on interprete text
263 contexte = self.get_contexte_jdc(fichier,text)
264 if contexte == None :
265 raise Exception("Impossible de construire le jeu de commandes correspondant au fichier")
267 # Pour les macros de type include : INCLUDE, INCLUDE_MATERIAU et POURSUITE
268 # l'attribut g_context est un dictionnaire qui contient les concepts produits par inclusion
269 # l'attribut contexte_fichier_init est un dictionnaire qui contient les concepts produits
270 # en sortie de macro. g_context est obtenu en retirant de contexte_fichier_init les concepts
271 # existants en debut de macro contenus dans context_ini (dans get_contexte_jdc)
272 # g_context est utilisé pour avoir les concepts produits par la macro
273 # contexte_fichier_init est utilisé pour avoir les concepts supprimés par la macro
274 self.contexte_fichier_init = contexte
276 def reevalue_fichier_init(self):
277 """Recalcule les concepts produits par le fichier enregistre"""
278 old_context=self.contexte_fichier_init
280 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
282 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
283 self.fichier_err = string.join(l)
287 self.old_contexte_fichier_init=old_context
288 self.contexte_fichier_init={}
289 self.reevalue_sd_jdc()
292 # L'evaluation s'est bien passee
293 self.fichier_err = None
294 self.old_contexte_fichier_init=old_context
295 self.reevalue_sd_jdc()
297 def update_fichier_init(self,unite):
298 """Reevalue le fichier init sans demander (dans la mesure du possible) a l'utilisateur
299 les noms des fichiers
300 Ceci suppose que les relations entre unites et noms ont été memorisees préalablement
302 #print "update_fichier_init",unite
303 self.fichier_err=None
304 self.old_contexte_fichier_init=self.contexte_fichier_init
306 #print self,self.parent,self.parent.recorded_units
307 #if unite != self.fichier_unite or not self.parent.recorded_units.has_key(unite):
308 if not self.parent.recorded_units.has_key(unite):
309 # Changement d'unite ou Nouvelle unite
310 f,text=self.get_file(unite=unite,fic_origine=self.parent.nom)
314 self.fichier_text=text
315 self.recorded_units=units
316 if self.fichier_ini is None and self.jdc.appli:
317 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
318 message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
320 # Meme unite existante
321 f,text,units=self.parent.recorded_units[unite]
323 self.fichier_text=text
324 self.recorded_units=units
326 if self.fichier_ini is None:
327 # Le fichier n'est pas défini
328 self.fichier_err="Le fichier associé n'est pas défini"
329 self.parent.change_unit(unite,self,self.fichier_unite)
331 self.contexte_fichier_init={}
332 self.parent.reset_context()
333 self.reevalue_sd_jdc()
337 self.make_contexte_include(self.fichier_ini,self.fichier_text)
338 # Les 3 attributs fichier_ini fichier_text recorded_units doivent etre corrects
339 # avant d'appeler change_unit
340 self.parent.change_unit(unite,self,self.fichier_unite)
342 # Erreurs lors de l'evaluation de text dans un JDC auxiliaire
343 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
344 # On conserve la memoire du nouveau fichier
345 # mais on n'utilise pas les concepts crees par ce fichier
346 # on met l'etape en erreur : fichier_err=string.join(l)
347 self.fichier_err=string.join(l)
348 self.parent.change_unit(unite,self,self.fichier_unite)
350 self.contexte_fichier_init={}
352 # Le contexte du parent doit etre reinitialise car les concepts
353 # produits ont changé
354 self.parent.reset_context()
355 # Si des concepts ont disparu lors du changement de fichier, on
356 # 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
370 #print "get_file_memo",unite,fic_origine,self,self.parent
371 #print self.parent.old_recorded_units
372 #print self.parent.recorded_units
376 units=self.parent.recorded_units
377 if self.parent.old_recorded_units.has_key(unite):
378 f,text,units=self.parent.old_recorded_units[unite]
379 #print id(self.recorded_units)
380 self.recorded_units=units
381 #print id(self.recorded_units)
384 f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
387 self.recorded_units=units
388 if f is None and self.jdc.appli:
389 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
390 message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
393 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
394 def get_file(self,unite=None,fic_origine=''):
395 """Retourne le nom du fichier et le source correspondant a l'unite unite
396 Initialise en plus recorded_units
398 #print "get_file",unite
401 f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
404 self.recorded_units=units
407 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
408 def make_include(self,unite=None):
410 Inclut un fichier dont l'unite logique est unite
411 Cette methode est appelee par la fonction sd_prod de la macro INCLUDE
412 Si l'INCLUDE est invalide, la methode doit produire une exception
413 Sinon on retourne None. Les concepts produits par l'INCLUDE sont
414 pris en compte par le JDC parent lors du calcul du contexte (appel de ???)
416 #print "make_include",unite
417 # On supprime l'attribut unite qui bloque l'evaluation du source de l'INCLUDE
418 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
420 # Si unite n'a pas de valeur, l'etape est forcement invalide. On peut retourner None
421 if not unite : return
423 if not hasattr(self,'fichier_ini') :
424 # Si le fichier n'est pas defini on le demande
425 f,text=self.get_file_memo(unite=unite,fic_origine=self.parent.nom)
426 # On memorise le fichier retourne
428 self.fichier_text = text
429 self.contexte_fichier_init={}
430 self.fichier_unite=unite
431 self.fichier_err=None
432 import Extensions.jdc_include
433 self.JdC_aux=Extensions.jdc_include.JdC_include
436 self.fichier_err="Le fichier INCLUDE n est pas defini"
437 self.parent.record_unit(unite,self)
438 raise Exception(self.fichier_err)
441 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
442 self.parent.record_unit(unite,self)
444 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
446 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
447 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
449 self.parent.record_unit(unite,self)
451 self.fichier_err = string.join(l)
452 self.contexte_fichier_init={}
456 # Si le fichier est deja defini on ne reevalue pas le fichier
457 # et on leve une exception si une erreur a été enregistrée
458 self.update_fichier_init(unite)
459 self.fichier_unite=unite
460 if self.fichier_err is not None: raise Exception(self.fichier_err)
463 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
464 def make_contexte(self,fichier,text):
466 Cette méthode sert à créer un contexte pour INCLUDE_MATERIAU
467 en interprétant un texte source Python
468 Elle est appelee par la fonction sd_prd d'INCLUDE_MATERIAU
470 # On supprime l'attribut mat qui bloque l'evaluation du source de l'INCLUDE_MATERIAU
471 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
472 if hasattr(self,'mat'):del self.mat
473 self.fichier_ini =fichier
474 self.fichier_unite =fichier
475 self.fichier_text=text
476 self.fichier_err=None
477 self.contexte_fichier_init={}
478 # On specifie la classe a utiliser pour le JDC auxiliaire
479 import Extensions.jdc_include
480 self.JdC_aux=Extensions.jdc_include.JdC_include
482 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
483 self.parent.record_unit(self.fichier_unite,self)
485 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
486 self.fichier_err = string.join(l)
487 self.parent.record_unit(self.fichier_unite,self)
489 self.contexte_fichier_init={}
492 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
493 def update_sdprod(self,cr='non'):
494 # Cette methode peut etre appelee dans EFICAS avec des mots cles de
495 # la commande modifies. Ceci peut conduire a la construction ou
496 # a la reconstruction d'etapes dans le cas d'INCLUDE ou d'INCLUDE_MATERIAU
497 # Il faut donc positionner le current_step avant l'appel
498 if self.state == "undetermined":return 1
499 CONTEXT.unset_current_step()
500 CONTEXT.set_current_step(self)
501 valid=Validation.V_MACRO_ETAPE.MACRO_ETAPE.update_sdprod(self,cr=cr)
502 CONTEXT.unset_current_step()
505 #ATTENTION SURCHARGE: cette methode surcharge celle de Noyau a garder en synchro
506 def Build_sd(self,nom):
508 Methode de Noyau surchargee pour poursuivre malgre tout
509 si une erreur se produit pendant la creation du concept produit
512 sd=Noyau.N_MACRO_ETAPE.MACRO_ETAPE.Build_sd(self,nom)
513 except AsException,e:
514 # Une erreur s'est produite lors de la construction du concept
515 # Comme on est dans EFICAS, on essaie de poursuivre quand meme
516 # Si on poursuit, on a le choix entre deux possibilités :
517 # 1. on annule la sd associée à self
518 # 2. on la conserve mais il faut la retourner
519 # On choisit de l'annuler
520 # En plus il faut rendre coherents sdnom et sd.nom
523 self.state="unchanged"
528 #ATTENTION SURCHARGE: cette methode surcharge celle de Noyau a garder en synchro
529 def make_poursuite(self):
530 """ Cette methode est appelée par la fonction sd_prod de la macro POURSUITE
532 if not hasattr(self,'fichier_ini') :
533 # Si le fichier n'est pas defini on le demande
534 f,text=self.get_file_memo(fic_origine=self.parent.nom)
535 # On memorise le fichier retourne
537 self.fichier_unite = None
538 self.fichier_text = text
539 self.fichier_err=None
540 import Extensions.jdc_include
541 self.JdC_aux=Extensions.jdc_include.JdC_poursuite
542 self.contexte_fichier_init={}
545 self.fichier_err="Le fichier POURSUITE n'est pas defini"
546 self.parent.record_unit(None,self)
547 raise Exception(self.fichier_err)
550 self.make_contexte_include(self.fichier_ini,self.fichier_text)
551 self.parent.record_unit(None,self)
553 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
555 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier poursuite",
556 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
558 self.parent.record_unit(None,self)
560 self.fichier_err = string.join(l)
561 self.contexte_fichier_init={}
565 # Si le fichier est deja defini on ne reevalue pas le fichier
566 # et on leve une exception si une erreur a été enregistrée
567 self.update_fichier_init(None)
568 if self.fichier_err is not None: raise Exception(self.fichier_err)