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 print "get_contexte_jdc",id(self.etapes)
103 traceback.print_exc()
104 # On force le contexte (etape courante) à self
105 CONTEXT.unset_current_step()
106 CONTEXT.set_current_step(self)
109 if not j.cr.estvide():
110 # Erreurs dans l'INCLUDE. On garde la memoire du fichier
111 # mais on n'insere pas les concepts
112 # On force le contexte (etape courante) à self
113 CONTEXT.unset_current_step()
114 CONTEXT.set_current_step(self)
115 raise Exception("Impossible de relire le fichier\n"+str(j.cr))
118 # L'INCLUDE n'est pas valide.
119 # on produit un rapport d'erreurs
120 # On force le contexte (etape courante) à self
122 CONTEXT.unset_current_step()
123 CONTEXT.set_current_step(self)
124 raise Exception("Le fichier include contient des erreurs\n"+str(cr))
126 # Si aucune erreur rencontrée
127 # On recupere le contexte de l'include verifie
129 j_context=j.get_verif_contexte()
131 CONTEXT.unset_current_step()
132 CONTEXT.set_current_step(self)
135 # On remplit le dictionnaire des concepts produits inclus
136 # en retirant les concepts présents dans le contexte initial
137 # On ajoute egalement le concept produit dans le sds_dict du parent
138 # sans verification car on est sur (verification integrée) que
139 # le nommage est possible
140 self.g_context.clear()
141 for k,v in j_context.items():
142 if not context_ini.has_key(k) or context_ini[k] != v:
144 self.parent.sds_dict[k]=v
147 # On recupere le contexte courant
148 self.current_context=j.current_context
149 self.index_etape_courante=j.index_etape_courante
152 # XXX j.supprime() ???
153 # On rétablit le contexte (etape courante) à self
154 CONTEXT.unset_current_step()
155 CONTEXT.set_current_step(self)
159 def reevalue_sd_jdc(self):
161 Avec la liste des SD qui ont été supprimées, propage la
162 disparition de ces SD dans toutes les étapes et descendants
164 l_sd_supp,l_sd_repl = self.diff_contextes()
166 self.parent.delete_concept_after_etape(self,sd)
167 for old_sd,sd in l_sd_repl:
168 self.parent.replace_concept_after_etape(self,old_sd,sd)
170 def diff_contextes(self):
172 Réalise la différence entre les 2 contextes
173 old_contexte_fichier_init et contexte_fichier_init
174 cad retourne la liste des sd qui ont disparu ou ne derivent pas
175 de la meme classe et des sd qui ont ete remplacees
177 if not hasattr(self,'old_contexte_fichier_init'):return [],[]
180 for old_key in self.old_contexte_fichier_init.keys():
181 if not self.contexte_fichier_init.has_key(old_key):
182 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
183 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
185 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
186 # Un concept de meme nom existe
187 old_class=self.old_contexte_fichier_init[old_key].__class__
188 if not isinstance(self.contexte_fichier_init[old_key],old_class):
189 # S'il n'est pas d'une classe derivee, on le supprime
190 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
192 l_sd_replaced.append((self.old_contexte_fichier_init[old_key],self.contexte_fichier_init[old_key]))
193 return l_sd_suppressed,l_sd_replaced
195 def control_sdprods(self,d):
197 Cette methode doit updater le contexte fournit par
198 l'appelant en argument (d) en fonction de sa definition
199 tout en verifiant que ses concepts produits ne sont pas
200 deja definis dans le contexte
202 if hasattr(self,"fichier_unite"):
203 self.update_fichier_init(self.fichier_unite)
206 if type(self.definition.op_init) == types.FunctionType:
207 apply(self.definition.op_init,(self,d))
209 if d.has_key(self.sd.nom):
210 # Le concept est deja defini
211 if self.reuse and self.reuse is d[self.sd.nom]:
212 # Le concept est reutilise : situation normale
215 # Redefinition du concept, on l'annule
216 #XXX on pourrait simplement annuler son nom pour conserver les objets
217 # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
218 self.sd=self.reuse=self.sdnom=None
221 # Le concept n'est pas defini, on peut updater d
222 d[self.sd.nom]=self.sd
223 # On verifie les concepts a droite du signe =
224 for co in self.sdprods:
225 if d.has_key(co.nom) and co is not d[co.nom] :
226 self.delete_concept(co)
231 def supprime_sdprods(self):
234 Lors d'une destruction d'etape, detruit tous les concepts produits
235 Un opérateur n a qu un concept produit
236 Une procedure n'en a aucun
237 Une macro en a en général plus d'un
239 if not self.is_reentrant() :
240 # l'étape n'est pas réentrante
241 # le concept retourné par l'étape est à supprimer car il était
244 self.parent.del_sdprod(self.sd)
245 self.parent.delete_concept(self.sd)
246 # On détruit les concepts à droite du signe =
247 for co in self.sdprods:
248 self.parent.del_sdprod(co)
249 self.parent.delete_concept(co)
250 # Si la macro a des etapes et des concepts inclus, on les detruit
251 for nom_sd,co in self.g_context.items():
252 if not isinstance(co,ASSD):continue
253 self.parent.del_sdprod(co)
254 self.parent.delete_concept(co)
255 # On met g_context à blanc
258 def make_contexte_include(self,fichier,text):
260 Cette méthode sert à créer un contexte en interprétant un texte source
263 print "make_contexte_include"
264 # on récupère le contexte d'un nouveau jdc dans lequel on interprete text
265 contexte = self.get_contexte_jdc(fichier,text)
266 if contexte == None :
267 raise Exception("Impossible de construire le jeu de commandes correspondant au fichier")
269 # Pour les macros de type include : INCLUDE, INCLUDE_MATERIAU et POURSUITE
270 # l'attribut g_context est un dictionnaire qui contient les concepts produits par inclusion
271 # l'attribut contexte_fichier_init est un dictionnaire qui contient les concepts produits
272 # en sortie de macro. g_context est obtenu en retirant de contexte_fichier_init les concepts
273 # existants en debut de macro contenus dans context_ini (dans get_contexte_jdc)
274 # g_context est utilisé pour avoir les concepts produits par la macro
275 # contexte_fichier_init est utilisé pour avoir les concepts supprimés par la macro
276 self.contexte_fichier_init = contexte
278 def reevalue_fichier_init(self):
279 """Recalcule les concepts produits par le fichier enregistre"""
280 old_context=self.contexte_fichier_init
282 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
284 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
285 self.fichier_err = string.join(l)
289 self.old_contexte_fichier_init=old_context
290 self.contexte_fichier_init={}
291 self.reevalue_sd_jdc()
294 # L'evaluation s'est bien passee
295 self.fichier_err = None
296 self.old_contexte_fichier_init=old_context
297 self.reevalue_sd_jdc()
299 def update_fichier_init(self,unite):
300 """Reevalue le fichier init sans demander (dans la mesure du possible) a l'utilisateur
301 les noms des fichiers
302 Ceci suppose que les relations entre unites et noms ont été memorisees préalablement
304 print "update_fichier_init",unite
305 self.fichier_err=None
306 self.old_contexte_fichier_init=self.contexte_fichier_init
307 old_fichier_ini=self.fichier_ini
309 #print "update_fichier_init",self,self.parent,self.parent.recorded_units
311 #if unite != self.fichier_unite or not self.parent.recorded_units.has_key(unite):
312 if not self.parent.recorded_units.has_key(unite):
314 f,text=self.get_file(unite=unite,fic_origine=self.parent.nom)
318 self.fichier_text=text
319 self.recorded_units=units
320 if self.fichier_ini is None and self.jdc.appli:
321 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
322 message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
325 f,text,units=self.parent.recorded_units[unite]
327 self.fichier_text=text
328 self.recorded_units=units
330 if self.fichier_ini is None:
331 # Le fichier n'est pas défini
332 self.fichier_err="Le fichier associé n'est pas défini"
333 self.parent.change_unit(unite,self,self.fichier_unite)
335 self.contexte_fichier_init={}
336 self.parent.reset_context()
337 self.reevalue_sd_jdc()
340 if old_fichier_ini == self.fichier_ini:
341 # Le fichier inclus n'a pas changé. On ne recrée pas le contexte
345 self.make_contexte_include(self.fichier_ini,self.fichier_text)
346 # Les 3 attributs fichier_ini fichier_text recorded_units doivent etre corrects
347 # avant d'appeler change_unit
348 self.parent.change_unit(unite,self,self.fichier_unite)
350 # Erreurs lors de l'evaluation de text dans un JDC auxiliaire
351 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
352 # On conserve la memoire du nouveau fichier
353 # mais on n'utilise pas les concepts crees par ce fichier
354 # on met l'etape en erreur : fichier_err=string.join(l)
355 self.fichier_err=string.join(l)
356 self.parent.change_unit(unite,self,self.fichier_unite)
358 self.contexte_fichier_init={}
360 # Le contexte du parent doit etre reinitialise car les concepts
361 # produits ont changé
362 self.parent.reset_context()
363 # Si des concepts ont disparu lors du changement de fichier, on
364 # demande leur suppression
365 self.reevalue_sd_jdc()
367 def record_unite(self):
368 if self.nom == "POURSUITE":
369 self.parent.record_unit(None,self)
371 if hasattr(self,'fichier_unite') :
372 self.parent.record_unit(self.fichier_unite,self)
374 def get_file_memo(self,unite=None,fic_origine=''):
375 """Retourne le nom du fichier et le source correspondant a l'unite unite
376 Initialise en plus recorded_units
378 #print "get_file_memo",unite,fic_origine,self,self.parent
379 #print self.parent.old_recorded_units
380 #print self.parent.recorded_units
384 units=self.parent.recorded_units
385 if self.parent.old_recorded_units.has_key(unite):
386 f,text,units=self.parent.old_recorded_units[unite]
387 #print id(self.recorded_units)
388 self.recorded_units=units
389 #print id(self.recorded_units)
392 f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
395 self.recorded_units=units
396 if f is None and self.jdc.appli:
397 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
398 message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
401 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
402 def get_file(self,unite=None,fic_origine=''):
403 """Retourne le nom du fichier et le source correspondant a l'unite unite
404 Initialise en plus recorded_units
406 #print "get_file",unite
409 f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
412 self.recorded_units=units
415 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
416 def make_include(self,unite=None):
418 Inclut un fichier dont l'unite logique est unite
419 Cette methode est appelee par la fonction sd_prod de la macro INCLUDE
420 Si l'INCLUDE est invalide, la methode doit produire une exception
421 Sinon on retourne None. Les concepts produits par l'INCLUDE sont
422 pris en compte par le JDC parent lors du calcul du contexte (appel de ???)
424 print "make_include",unite
425 # On supprime l'attribut unite qui bloque l'evaluation du source de l'INCLUDE
426 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
428 # Si unite n'a pas de valeur, l'etape est forcement invalide. On peut retourner None
429 if not unite : return
431 if not hasattr(self,'fichier_ini') :
432 # Si le fichier n'est pas defini on le demande
433 f,text=self.get_file_memo(unite=unite,fic_origine=self.parent.nom)
434 # On memorise le fichier retourne
436 self.fichier_text = text
437 self.contexte_fichier_init={}
438 self.fichier_unite=unite
439 self.fichier_err=None
441 import Extensions.jdc_include
443 traceback.print_exc()
445 self.JdC_aux=Extensions.jdc_include.JdC_include
448 self.fichier_err="Le fichier INCLUDE n est pas defini"
449 self.parent.record_unit(unite,self)
450 raise Exception(self.fichier_err)
453 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
454 self.parent.record_unit(unite,self)
456 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
458 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
459 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
461 self.parent.record_unit(unite,self)
463 self.fichier_err = string.join(l)
464 self.contexte_fichier_init={}
468 # Si le fichier est deja defini on ne reevalue pas le fichier
469 # et on leve une exception si une erreur a été enregistrée
470 self.update_fichier_init(unite)
471 self.fichier_unite=unite
472 if self.fichier_err is not None: raise Exception(self.fichier_err)
475 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
476 def make_contexte(self,fichier,text):
478 Cette méthode sert à créer un contexte pour INCLUDE_MATERIAU
479 en interprétant un texte source Python
480 Elle est appelee par la fonction sd_prd d'INCLUDE_MATERIAU
482 # On supprime l'attribut mat qui bloque l'evaluation du source de l'INCLUDE_MATERIAU
483 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
484 if hasattr(self,'mat'):del self.mat
485 self.fichier_ini =fichier
486 self.fichier_unite =fichier
487 self.fichier_text=text
488 self.fichier_err=None
489 self.contexte_fichier_init={}
490 # On specifie la classe a utiliser pour le JDC auxiliaire
492 import Extensions.jdc_include
494 traceback.print_exc()
496 self.JdC_aux=Extensions.jdc_include.JdC_include
498 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
499 self.parent.record_unit(self.fichier_unite,self)
501 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
502 self.fichier_err = string.join(l)
503 self.parent.record_unit(self.fichier_unite,self)
505 self.contexte_fichier_init={}
508 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
509 def update_sdprod(self,cr='non'):
510 # Cette methode peut etre appelee dans EFICAS avec des mots cles de
511 # la commande modifies. Ceci peut conduire a la construction ou
512 # a la reconstruction d'etapes dans le cas d'INCLUDE ou d'INCLUDE_MATERIAU
513 # Il faut donc positionner le current_step avant l'appel
514 CONTEXT.unset_current_step()
515 CONTEXT.set_current_step(self)
516 valid=Validation.V_MACRO_ETAPE.MACRO_ETAPE.update_sdprod(self,cr=cr)
517 CONTEXT.unset_current_step()
520 #ATTENTION SURCHARGE: cette methode surcharge celle de Noyau a garder en synchro
521 def Build_sd(self,nom):
523 Methode de Noyau surchargee pour poursuivre malgre tout
524 si une erreur se produit pendant la creation du concept produit
527 sd=Noyau.N_MACRO_ETAPE.MACRO_ETAPE.Build_sd(self,nom)
528 except AsException,e:
529 # Une erreur s'est produite lors de la construction du concept
530 # Comme on est dans EFICAS, on essaie de poursuivre quand meme
531 # Si on poursuit, on a le choix entre deux possibilités :
532 # 1. on annule la sd associée à self
533 # 2. on la conserve mais il faut la retourner
534 # On choisit de l'annuler
535 # En plus il faut rendre coherents sdnom et sd.nom
538 self.state="unchanged"
543 #ATTENTION SURCHARGE: cette methode surcharge celle de Noyau a garder en synchro
544 def make_poursuite(self):
545 """ Cette methode est appelée par la fonction sd_prod de la macro POURSUITE
547 print "make_poursuite"
548 if not hasattr(self,'fichier_ini') :
549 # Si le fichier n'est pas defini on le demande
550 f,text=self.get_file_memo(fic_origine=self.parent.nom)
551 # On memorise le fichier retourne
553 self.fichier_unite = None
554 self.fichier_text = text
555 self.fichier_err=None
557 import Extensions.jdc_include
559 traceback.print_exc()
561 self.JdC_aux=Extensions.jdc_include.JdC_poursuite
562 self.contexte_fichier_init={}
565 self.fichier_err="Le fichier POURSUITE n'est pas defini"
566 self.parent.record_unit(None,self)
567 raise Exception(self.fichier_err)
570 self.make_contexte_include(self.fichier_ini,self.fichier_text)
571 self.parent.record_unit(None,self)
573 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
575 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier poursuite",
576 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
578 self.parent.record_unit(None,self)
580 self.fichier_err = string.join(l)
581 self.contexte_fichier_init={}
585 # Si le fichier est deja defini on ne reevalue pas le fichier
586 # et on leve une exception si une erreur a été enregistrée
587 self.update_fichier_init(None)
588 if self.fichier_err is not None: raise Exception(self.fichier_err)