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
79 # clear plutot) 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
106 # mais on n'insere pas les concepts
107 # On force le contexte (etape courante) à self
108 CONTEXT.unset_current_step()
109 CONTEXT.set_current_step(self)
110 raise Exception("Impossible de relire le fichier\n"+str(j.cr))
113 # L'INCLUDE n'est pas valide.
114 # on produit un rapport d'erreurs
115 # On force le contexte (etape courante) à self
117 CONTEXT.unset_current_step()
118 CONTEXT.set_current_step(self)
119 raise Exception("Le fichier include contient des erreurs\n"+str(cr))
121 # Si aucune erreur rencontrée
122 # On recupere le contexte de l'include verifie
124 j_context=j.get_verif_contexte()
126 CONTEXT.unset_current_step()
127 CONTEXT.set_current_step(self)
130 # On remplit le dictionnaire des concepts produits inclus
131 # en retirant les concepts présents dans le contexte initial
132 # On ajoute egalement le concept produit dans le sds_dict du parent
133 # sans verification car on est sur (verification integrée) que
134 # le nommage est possible
135 self.g_context.clear()
136 for k,v in j_context.items():
137 if not context_ini.has_key(k) or context_ini[k] != v:
139 self.parent.sds_dict[k]=v
142 # On recupere le contexte courant
143 self.current_context=j.current_context
144 self.index_etape_courante=j.index_etape_courante
146 # XXX j.supprime() ???
147 # On rétablit le contexte (etape courante) à self
148 CONTEXT.unset_current_step()
149 CONTEXT.set_current_step(self)
153 def reevalue_sd_jdc(self):
155 Avec la liste des SD qui ont été supprimées, propage la
156 disparition de ces SD dans toutes les étapes et descendants
158 l_sd_supp,l_sd_repl = self.diff_contextes()
160 self.parent.delete_concept_after_etape(self,sd)
161 for old_sd,sd in l_sd_repl:
162 self.parent.replace_concept_after_etape(self,old_sd,sd)
164 def diff_contextes(self):
166 Réalise la différence entre les 2 contextes
167 old_contexte_fichier_init et contexte_fichier_init
168 cad retourne la liste des sd qui ont disparu ou ne derivent pas
169 de la meme classe et des sd qui ont ete remplacees
171 if not hasattr(self,'old_contexte_fichier_init'):return [],[]
174 for old_key in self.old_contexte_fichier_init.keys():
175 if not self.contexte_fichier_init.has_key(old_key):
176 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
177 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
179 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
180 # Un concept de meme nom existe
181 old_class=self.old_contexte_fichier_init[old_key].__class__
182 if not isinstance(self.contexte_fichier_init[old_key],old_class):
183 # S'il n'est pas d'une classe derivee, on le supprime
184 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
186 l_sd_replaced.append((self.old_contexte_fichier_init[old_key],self.contexte_fichier_init[old_key]))
187 return l_sd_suppressed,l_sd_replaced
189 def control_sdprods(self,d):
191 Cette methode doit updater le contexte fournit par
192 l'appelant en argument (d) en fonction de sa definition
193 tout en verifiant que ses concepts produits ne sont pas
194 deja definis dans le contexte
196 if hasattr(self,"fichier_unite"):
197 self.update_fichier_init(self.fichier_unite)
200 if type(self.definition.op_init) == types.FunctionType:
201 apply(self.definition.op_init,(self,d))
203 if d.has_key(self.sd.nom):
204 # Le concept est deja defini
205 if self.reuse and self.reuse is d[self.sd.nom]:
206 # Le concept est reutilise : situation normale
209 # Redefinition du concept, on l'annule
210 #XXX on pourrait simplement annuler son nom pour conserver les objets
211 # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
212 self.sd=self.reuse=self.sdnom=None
215 # Le concept n'est pas defini, on peut updater d
216 d[self.sd.nom]=self.sd
217 # On verifie les concepts a droite du signe =
218 for co in self.sdprods:
219 if d.has_key(co.nom) and co is not d[co.nom] :
220 self.delete_concept(co)
225 def supprime_sdprods(self):
228 Lors d'une destruction d'etape, detruit tous les concepts produits
229 Un opérateur n a qu un concept produit
230 Une procedure n'en a aucun
231 Une macro en a en général plus d'un
233 if not self.is_reentrant() :
234 # l'étape n'est pas réentrante
235 # le concept retourné par l'étape est à supprimer car il était
238 self.parent.del_sdprod(self.sd)
239 self.parent.delete_concept(self.sd)
240 # On détruit les concepts à droite du signe =
241 for co in self.sdprods:
242 self.parent.del_sdprod(co)
243 self.parent.delete_concept(co)
244 # Si la macro a des etapes et des concepts inclus, on les detruit
245 for nom_sd,co in self.g_context.items():
246 if not isinstance(co,ASSD):continue
247 self.parent.del_sdprod(co)
248 self.parent.delete_concept(co)
249 # On met g_context à blanc
252 def make_contexte_include(self,fichier,text):
254 Cette méthode sert à créer un contexte en interprétant un texte source
257 # on récupère le contexte d'un nouveau jdc dans lequel on interprete text
258 contexte = self.get_contexte_jdc(fichier,text)
259 if contexte == None :
260 raise Exception("Impossible de construire le jeu de commandes correspondant au fichier")
262 # Pour les macros de type include : INCLUDE, INCLUDE_MATERIAU et POURSUITE
263 # l'attribut g_context est un dictionnaire qui contient les concepts produits par inclusion
264 # l'attribut contexte_fichier_init est un dictionnaire qui contient les concepts produits
265 # en sortie de macro. g_context est obtenu en retirant de contexte_fichier_init les concepts
266 # existants en debut de macro contenus dans context_ini (dans get_contexte_jdc)
267 # g_context est utilisé pour avoir les concepts produits par la macro
268 # contexte_fichier_init est utilisé pour avoir les concepts supprimés par la macro
269 self.contexte_fichier_init = contexte
271 def reevalue_fichier_init(self):
272 """Recalcule les concepts produits par le fichier enregistre"""
273 old_context=self.contexte_fichier_init
275 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
277 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
278 self.fichier_err = string.join(l)
282 self.old_contexte_fichier_init=old_context
283 self.contexte_fichier_init={}
284 self.reevalue_sd_jdc()
287 # L'evaluation s'est bien passee
288 self.fichier_err = None
289 self.old_contexte_fichier_init=old_context
290 self.reevalue_sd_jdc()
292 def update_fichier_init(self,unite):
293 """Reevalue le fichier init sans demander (dans la mesure du possible) a l'utilisateur
294 les noms des fichiers
295 Ceci suppose que les relations entre unites et noms ont été memorisees préalablement
298 self.fichier_err=None
299 self.old_contexte_fichier_init=self.contexte_fichier_init
301 if unite != self.fichier_unite or not self.parent.recorded_units.has_key(unite):
302 # Changement d'unite ou Nouvelle unite
303 f,text=self.get_file(unite=unite,fic_origine=self.parent.nom)
307 self.fichier_text=text
308 self.recorded_units=units
309 if self.fichier_ini is None and self.jdc.appli:
310 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
311 message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
313 # Meme unite existante
314 f,text,units=self.parent.recorded_units[unite]
316 self.fichier_text=text
317 self.recorded_units=units
319 if self.fichier_ini is None:
320 # Le fichier n'est pas défini
321 self.fichier_err="Le fichier associé n'est pas défini"
322 self.parent.change_unit(unite,self,self.fichier_unite)
324 self.contexte_fichier_init={}
325 self.parent.reset_context()
326 self.reevalue_sd_jdc()
330 self.make_contexte_include(self.fichier_ini,self.fichier_text)
331 # Les 3 attributs fichier_ini fichier_text recorded_units doivent etre corrects
332 # avant d'appeler change_unit
333 self.parent.change_unit(unite,self,self.fichier_unite)
335 # Erreurs lors de l'evaluation de text dans un JDC auxiliaire
336 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
337 # On conserve la memoire du nouveau fichier
338 # mais on n'utilise pas les concepts crees par ce fichier
339 # on met l'etape en erreur : fichier_err=string.join(l)
340 self.fichier_err=string.join(l)
341 self.parent.change_unit(unite,self,self.fichier_unite)
343 self.contexte_fichier_init={}
345 # Le contexte du parent doit etre reinitialise car les concepts
346 # produits ont changé
347 self.parent.reset_context()
348 # Si des concepts ont disparu lors du changement de fichier, on
349 # demande leur suppression
350 self.reevalue_sd_jdc()
352 def record_unite(self):
353 if self.nom == "POURSUITE":
354 self.parent.record_unit(None,self)
356 if hasattr(self,'fichier_unite') :
357 self.parent.record_unit(self.fichier_unite,self)
359 def get_file_memo(self,unite=None,fic_origine=''):
360 """Retourne le nom du fichier et le source correspondant a l'unite unite
361 Initialise en plus recorded_units
364 if self.parent.old_recorded_units.has_key(unite):
365 f,text,units=self.parent.old_recorded_units[unite]
366 self.recorded_units=units
369 f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
372 self.recorded_units=units
373 if f is None and self.jdc.appli:
374 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
375 message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
378 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
379 def get_file(self,unite=None,fic_origine=''):
380 """Retourne le nom du fichier et le source correspondant a l'unite unite
381 Initialise en plus recorded_units
385 f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
388 self.recorded_units=units
391 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
392 def make_include(self,unite=None):
394 Inclut un fichier dont l'unite logique est unite
395 Cette methode est appelee par la fonction sd_prod de la macro INCLUDE
396 Si l'INCLUDE est invalide, la methode doit produire une exception
397 Sinon on retourne None. Les concepts produits par l'INCLUDE sont
398 pris en compte par le JDC parent lors du calcul du contexte (appel de ???)
401 # On supprime l'attribut unite qui bloque l'evaluation du source de l'INCLUDE
402 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
404 # Si unite n'a pas de valeur, l'etape est forcement invalide. On peut retourner None
405 if not unite : return
407 if not hasattr(self,'fichier_ini') :
408 # Si le fichier n'est pas defini on le demande
409 f,text=self.get_file_memo(unite=unite,fic_origine=self.parent.nom)
410 # On memorise le fichier retourne
412 self.fichier_text = text
413 self.contexte_fichier_init={}
414 self.fichier_unite=unite
415 self.fichier_err=None
416 import Extensions.jdc_include
417 self.JdC_aux=Extensions.jdc_include.JdC_include
420 self.fichier_err="Le fichier INCLUDE n est pas defini"
421 self.parent.record_unit(unite,self)
422 raise Exception(self.fichier_err)
425 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
426 self.parent.record_unit(unite,self)
428 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
430 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
431 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
433 self.parent.record_unit(unite,self)
435 self.fichier_err = string.join(l)
436 self.contexte_fichier_init={}
440 # Si le fichier est deja defini on ne reevalue pas le fichier
441 # et on leve une exception si une erreur a été enregistrée
442 self.update_fichier_init(unite)
443 self.fichier_unite=unite
444 if self.fichier_err is not None: raise Exception(self.fichier_err)
447 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
448 def make_contexte(self,fichier,text):
450 Cette méthode sert à créer un contexte pour INCLUDE_MATERIAU
451 en interprétant un texte source Python
452 Elle est appelee par la fonction sd_prd d'INCLUDE_MATERIAU
454 # On supprime l'attribut mat qui bloque l'evaluation du source de l'INCLUDE_MATERIAU
455 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
456 if hasattr(self,'mat'):del self.mat
457 self.fichier_ini =fichier
458 self.fichier_unite =fichier
459 self.fichier_text=text
460 self.fichier_err=None
461 self.contexte_fichier_init={}
462 # On specifie la classe a utiliser pour le JDC auxiliaire
463 import Extensions.jdc_include
464 self.JdC_aux=Extensions.jdc_include.JdC_include
466 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
467 self.parent.record_unit(self.fichier_unite,self)
469 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
470 self.fichier_err = string.join(l)
471 self.parent.record_unit(self.fichier_unite,self)
473 self.contexte_fichier_init={}
476 #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro)
477 def update_sdprod(self,cr='non'):
478 # Cette methode peut etre appelee dans EFICAS avec des mots cles de
479 # la commande modifies. Ceci peut conduire a la construction ou
480 # a la reconstruction d'etapes dans le cas d'INCLUDE ou d'INCLUDE_MATERIAU
481 # Il faut donc positionner le current_step avant l'appel
482 if self.state == "undetermined":return 1
483 CONTEXT.unset_current_step()
484 CONTEXT.set_current_step(self)
485 valid=Validation.V_MACRO_ETAPE.MACRO_ETAPE.update_sdprod(self,cr=cr)
486 CONTEXT.unset_current_step()
489 #ATTENTION SURCHARGE: cette methode surcharge celle de Noyau a garder en synchro
490 def Build_sd(self,nom):
492 Methode de Noyau surchargee pour poursuivre malgre tout
493 si une erreur se produit pendant la creation du concept produit
496 sd=Noyau.N_MACRO_ETAPE.MACRO_ETAPE.Build_sd(self,nom)
497 except AsException,e:
498 # Une erreur s'est produite lors de la construction du concept
499 # Comme on est dans EFICAS, on essaie de poursuivre quand meme
500 # Si on poursuit, on a le choix entre deux possibilités :
501 # 1. on annule la sd associée à self
502 # 2. on la conserve mais il faut la retourner
503 # On choisit de l'annuler
504 # En plus il faut rendre coherents sdnom et sd.nom
507 self.state="unchanged"
512 #ATTENTION SURCHARGE: cette methode surcharge celle de Noyau a garder en synchro
513 def make_poursuite(self):
514 """ Cette methode est appelée par la fonction sd_prod de la macro POURSUITE
516 if not hasattr(self,'fichier_ini') :
517 # Si le fichier n'est pas defini on le demande
518 f,text=self.get_file_memo(fic_origine=self.parent.nom)
519 # On memorise le fichier retourne
521 self.fichier_unite = None
522 self.fichier_text = text
523 self.fichier_err=None
524 import Extensions.jdc_include
525 self.JdC_aux=Extensions.jdc_include.JdC_poursuite
526 self.contexte_fichier_init={}
529 self.fichier_err="Le fichier POURSUITE n'est pas defini"
530 self.parent.record_unit(None,self)
531 raise Exception(self.fichier_err)
534 self.make_contexte_include(self.fichier_ini,self.fichier_text)
535 self.parent.record_unit(None,self)
537 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
539 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier poursuite",
540 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
542 self.parent.record_unit(None,self)
544 self.fichier_err = string.join(l)
545 self.contexte_fichier_init={}
549 # Si le fichier est deja defini on ne reevalue pas le fichier
550 # et on leve une exception si une erreur a été enregistrée
551 self.update_fichier_init(None)
552 if self.fichier_err is not None: raise Exception(self.fichier_err)