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
75 # ATTENTION : le dictionnaire recorded_units sert à memoriser les unites des
76 # fichiers inclus. Il est preferable de garder le meme dictionnaire pendant
77 # tout le traitement et de ne pas le reinitialiser brutalement (utiliser clear plutot)
78 # si on ne veut pas perdre la memoire des unites.
79 # En principe si la memorisation est faite au bon moment il n'est pas necessaire
80 # de prendre cette precaution mais ce n'est pas vrai partout.
81 old_recorded_units=self.recorded_units.copy()
82 self.recorded_units.clear()
84 j=self.JdC_aux( procedure=text,cata=self.jdc.cata,
86 context_ini = context_ini,
88 jdc_pere=self.jdc,etape_include=self,
89 prefix_include=prefix_include,
90 recorded_units=self.recorded_units,
91 old_recorded_units=old_recorded_units,**args)
94 # On récupère les étapes internes (pour validation)
98 # On force le contexte (etape courante) à self
99 CONTEXT.unset_current_step()
100 CONTEXT.set_current_step(self)
103 if not j.cr.estvide():
104 # Erreurs dans l'INCLUDE. On garde la memoire du fichier mais on n'insere pas les concepts
105 # On force le contexte (etape courante) à self
106 CONTEXT.unset_current_step()
107 CONTEXT.set_current_step(self)
108 raise Exception("Impossible de relire le fichier\n"+str(j.cr))
112 # On force le contexte (etape courante) à self
113 CONTEXT.unset_current_step()
114 CONTEXT.set_current_step(self)
115 raise Exception("Le fichier include contient des erreurs\n"+str(j.cr))
117 # On recupere le contexte apres la derniere etape
118 j_context=j.get_contexte_avant(None)
120 # Cette verification n'est plus necessaire elle est integree dans le JDC_INCLUDE
121 self.verif_contexte(j_context)
123 # On remplit le dictionnaire des concepts produits inclus
124 # en retirant les concepts présents dans le contexte initial
125 # On ajoute egalement le concept produit dans le sds_dict du parent
126 # sans verification car on est sur (verification integrée) que le nommage est possible
127 self.g_context.clear()
128 for k,v in j_context.items():
129 if not context_ini.has_key(k) or context_ini[k] != v:
131 self.parent.sds_dict[k]=v
134 # On recupere le contexte courant
135 self.current_context=j.current_context
136 self.index_etape_courante=j.index_etape_courante
138 # XXX j.supprime() ???
139 # On rétablit le contexte (etape courante) à self
140 CONTEXT.unset_current_step()
141 CONTEXT.set_current_step(self)
145 def verif_contexte(self,context):
147 On verifie que le contexte context peut etre inséré dans le jeu
148 de commandes à la position de self
150 for nom_sd,sd in context.items():
151 if not isinstance(sd,ASSD):continue
152 #if self.parent.get_sd_apres_etape(nom_sd,etape=self):
153 if self.parent.get_sd_apres_etape_avec_detruire(nom_sd,sd,etape=self):
154 # Il existe un concept produit par une etape apres self => impossible d'inserer
155 # On force le contexte (etape courante) à self
156 CONTEXT.unset_current_step()
157 CONTEXT.set_current_step(self)
158 raise Exception("Impossible d'inclure le fichier. Un concept de nom " +
159 "%s existe déjà dans le jeu de commandes." % nom_sd)
161 def reevalue_sd_jdc(self):
163 Avec la liste des SD qui ont été supprimées, propage la
164 disparition de ces SD dans toutes les étapes et descendants
166 l_sd_supp,l_sd_repl = self.diff_contextes()
168 self.parent.delete_concept_after_etape(self,sd)
169 for old_sd,sd in l_sd_repl:
170 self.parent.replace_concept_after_etape(self,old_sd,sd)
172 def diff_contextes(self):
174 Réalise la différence entre les 2 contextes
175 old_contexte_fichier_init et contexte_fichier_init
176 cad retourne la liste des sd qui ont disparu ou ne derivent pas de la meme classe
177 et des sd qui ont ete remplacees
179 if not hasattr(self,'old_contexte_fichier_init'):return [],[]
182 for old_key in self.old_contexte_fichier_init.keys():
183 if not self.contexte_fichier_init.has_key(old_key):
184 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
185 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
187 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
188 # Un concept de meme nom existe
189 old_class=self.old_contexte_fichier_init[old_key].__class__
190 if not isinstance(self.contexte_fichier_init[old_key],old_class):
191 # S'il n'est pas d'une classe derivee, on le supprime
192 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
194 l_sd_replaced.append((self.old_contexte_fichier_init[old_key],self.contexte_fichier_init[old_key]))
195 return l_sd_suppressed,l_sd_replaced
197 def control_sdprods(self,d):
199 Cette methode doit updater le contexte fournit par
200 l'appelant en argument (d) en fonction de sa definition
201 tout en verifiant que ses concepts produits ne sont pas
202 deja definis dans le contexte
204 if hasattr(self,"fichier_unite"):
205 self.update_fichier_init(self.fichier_unite)
208 if type(self.definition.op_init) == types.FunctionType:
209 apply(self.definition.op_init,(self,d))
211 if d.has_key(self.sd.nom):
212 # Le concept est deja defini
213 if self.reuse and self.reuse is d[self.sd.nom]:
214 # Le concept est reutilise : situation normale
217 # Redefinition du concept, on l'annule
218 #XXX on pourrait simplement annuler son nom pour conserver les objets
219 # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
220 self.sd=self.reuse=self.sdnom=None
223 # Le concept n'est pas defini, on peut updater d
224 d[self.sd.nom]=self.sd
225 # On verifie les concepts a droite du signe =
226 for co in self.sdprods:
227 if d.has_key(co.nom) and co is not d[co.nom] :
228 self.delete_concept(co)
233 def supprime_sdprods(self):
236 Lors d'une destruction d'etape, detruit tous les concepts produits
237 Un opérateur n a qu un concept produit
238 Une procedure n'en a aucun
239 Une macro en a en général plus d'un
241 if not self.is_reentrant() :
242 # l'étape n'est pas réentrante
243 # le concept retourné par l'étape est à supprimer car il était
246 self.parent.del_sdprod(self.sd)
247 self.parent.delete_concept(self.sd)
248 # On détruit les concepts à droite du signe =
249 for co in self.sdprods:
250 self.parent.del_sdprod(co)
251 self.parent.delete_concept(co)
252 # Si la macro a des etapes et des concepts inclus, on les detruit
253 for nom_sd,co in self.g_context.items():
254 if not isinstance(co,ASSD):continue
255 self.parent.del_sdprod(co)
256 self.parent.delete_concept(co)
257 # On met g_context à blanc
260 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
261 def Build_sd(self,nom):
263 Construit le concept produit de l'opérateur. Deux cas
264 peuvent se présenter :
266 - le parent n'est pas défini. Dans ce cas, l'étape prend en charge
267 la création et le nommage du concept.
269 - le parent est défini. Dans ce cas, l'étape demande au parent la
270 création et le nommage du concept.
273 if not self.isactif():return
274 # CCAR : meme modification que dans I_ETAPE
275 if not self.isvalid(sd='non') : return
278 # On positionne la macro self en tant que current_step pour que les
279 # étapes créées lors de l'appel à sd_prod et à op_init aient la macro
281 self.set_current_step()
283 sd= self.parent.create_sdprod(self,nom)
284 if type(self.definition.op_init) == types.FunctionType:
285 apply(self.definition.op_init,(self,self.parent.g_context))
287 sd=self.get_sd_prod()
288 if sd != None and self.reuse == None:
289 # On ne nomme le concept que dans le cas de non reutilisation
292 self.reset_current_step()
293 # Si on est arrive ici, l'etape est valide
294 self.state="unchanged"
296 if self.jdc and self.jdc.par_lot == "NON" :
299 except AsException,e:
300 self.reset_current_step()
301 # Une erreur s'est produite lors de la construction du concept
302 # Comme on est dans EFICAS, on essaie de poursuivre quand meme
303 # Si on poursuit, on a le choix entre deux possibilités :
304 # 1. on annule la sd associée à self
305 # 2. on la conserve mais il faut qu'elle soit correcte et la retourner
306 # En plus il faut rendre coherents sdnom et sd.nom
307 # On choisit de retourner None et de mettre l'etape invalide
310 self.state="unchanged"
313 #raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
314 # 'fichier : ',self.appel[1],e)
318 self.reset_current_step()
319 l=traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2])
320 raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
321 'fichier : ',self.appel[1]+'\n',
324 def make_contexte_include(self,fichier,text):
326 Cette méthode sert à créer un contexte en interprétant un texte source
329 # on récupère le contexte d'un nouveau jdc dans lequel on interprete text
330 contexte = self.get_contexte_jdc(fichier,text)
331 if contexte == None :
332 raise Exception("Impossible de construire le jeu de commandes correspondant au fichier")
334 # Pour les macros de type include : INCLUDE, INCLUDE_MATERIAU et POURSUITE
335 # l'attribut g_context est un dictionnaire qui contient les concepts produits par inclusion
336 # l'attribut contexte_fichier_init est un dictionnaire qui contient les concepts produits
337 # en sortie de macro. g_context est obtenu en retirant de contexte_fichier_init les concepts
338 # existants en debut de macro contenus dans context_ini (dans get_contexte_jdc)
339 # g_context est utilisé pour avoir les concepts produits par la macro
340 # contexte_fichier_init est utilisé pour avoir les concepts supprimés par la macro
341 self.contexte_fichier_init = contexte
343 def reevalue_fichier_init(self):
344 """Recalcule les concepts produits par le fichier enregistre"""
345 old_context=self.contexte_fichier_init
347 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
349 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
350 self.fichier_err = string.join(l)
354 self.old_contexte_fichier_init=old_context
355 self.contexte_fichier_init={}
356 self.reevalue_sd_jdc()
359 # L'evaluation s'est bien passee
360 self.fichier_err = None
361 self.old_contexte_fichier_init=old_context
362 self.reevalue_sd_jdc()
364 def update_fichier_init(self,unite):
365 """Reevalue le fichier init sans demander (dans la mesure du possible) a l'utilisateur
366 les noms des fichiers
367 Ceci suppose que les relations entre unites et noms ont été memorisees préalablement
370 self.fichier_err=None
371 self.old_contexte_fichier_init=self.contexte_fichier_init
373 if unite != self.fichier_unite or not self.parent.recorded_units.has_key(unite):
374 # Changement d'unite ou Nouvelle unite
375 f,text=self.get_file(unite=unite,fic_origine=self.parent.nom)
379 self.fichier_text=text
380 self.recorded_units=units
381 if self.fichier_ini is None and self.jdc.appli:
382 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
383 message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
385 # Meme unite existante
386 f,text,units=self.parent.recorded_units[unite]
388 self.fichier_text=text
389 self.recorded_units=units
391 if self.fichier_ini is None:
392 # Le fichier n'est pas défini
393 self.fichier_err="Le fichier associé n'est pas défini"
394 self.parent.change_unit(unite,self,self.fichier_unite)
396 self.contexte_fichier_init={}
397 self.parent.reset_context()
398 self.reevalue_sd_jdc()
402 self.make_contexte_include(self.fichier_ini,self.fichier_text)
403 # Les 3 attributs fichier_ini fichier_text recorded_units doivent etre corrects
404 # avant d'appeler change_unit
405 self.parent.change_unit(unite,self,self.fichier_unite)
407 # Erreurs lors de l'evaluation de text dans un JDC auxiliaire
408 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
409 # On conserve la memoire du nouveau fichier
410 # mais on n'utilise pas les concepts crees par ce fichier
411 # on met l'etape en erreur : fichier_err=string.join(l)
412 self.fichier_err=string.join(l)
413 self.parent.change_unit(unite,self,self.fichier_unite)
415 self.contexte_fichier_init={}
417 # Le contexte du parent doit etre reinitialise car les concepts produits ont changé
418 self.parent.reset_context()
419 # Si des concepts ont disparu lors du changement de fichier, on demande leur suppression
420 self.reevalue_sd_jdc()
422 def record_unite(self):
423 if self.nom == "POURSUITE":
424 self.parent.record_unit(None,self)
426 if hasattr(self,'fichier_unite') :
427 self.parent.record_unit(self.fichier_unite,self)
429 def make_poursuite(self):
430 """ Cette methode est appelée par la fonction sd_prod de la macro POURSUITE
432 if not hasattr(self,'fichier_ini') :
433 # Si le fichier n'est pas defini on le demande
434 f,text=self.get_file_memo(fic_origine=self.parent.nom)
435 # On memorise le fichier retourne
437 self.fichier_unite = None
438 self.fichier_text = text
439 self.fichier_err=None
440 import Extensions.jdc_include
441 self.JdC_aux=Extensions.jdc_include.JdC_poursuite
442 self.contexte_fichier_init={}
445 self.fichier_err="Le fichier POURSUITE n'est pas defini"
446 self.parent.record_unit(None,self)
447 raise Exception(self.fichier_err)
450 self.make_contexte_include(self.fichier_ini,self.fichier_text)
451 self.parent.record_unit(None,self)
453 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
455 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier poursuite",
456 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
458 self.parent.record_unit(None,self)
460 self.fichier_err = string.join(l)
461 self.contexte_fichier_init={}
465 # Si le fichier est deja defini on ne reevalue pas le fichier
466 # et on leve une exception si une erreur a été enregistrée
467 self.update_fichier_init(None)
468 if self.fichier_err is not None: raise Exception(self.fichier_err)
470 def get_file(self,unite=None,fic_origine=''):
471 """Retourne le nom du fichier et le source correspondant a l'unite unite
472 Initialise en plus recorded_units
476 f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
479 self.recorded_units=units
482 def get_file_memo(self,unite=None,fic_origine=''):
483 """Retourne le nom du fichier et le source correspondant a l'unite unite
484 Initialise en plus recorded_units
487 if self.parent.old_recorded_units.has_key(unite):
488 f,text,units=self.parent.old_recorded_units[unite]
489 self.recorded_units=units
492 f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
495 self.recorded_units=units
496 if f is None and self.jdc.appli:
497 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
498 message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
501 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
502 def make_include(self,unite=None):
504 Inclut un fichier dont l'unite logique est unite
505 Cette methode est appelee par la fonction sd_prod de la macro INCLUDE
506 Si l'INCLUDE est invalide, la methode doit produire une exception
507 Sinon on retourne None. Les concepts produits par l'INCLUDE sont
508 pris en compte par le JDC parent lors du calcul du contexte (appel de ???)
511 # On supprime l'attribut unite qui bloque l'evaluation du source de l'INCLUDE
512 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
514 # Si unite n'a pas de valeur, l'etape est forcement invalide. On peut retourner None
515 if not unite : return
517 if not hasattr(self,'fichier_ini') :
518 # Si le fichier n'est pas defini on le demande
519 f,text=self.get_file_memo(unite=unite,fic_origine=self.parent.nom)
520 # On memorise le fichier retourne
522 self.fichier_text = text
523 self.contexte_fichier_init={}
524 self.fichier_unite=unite
525 self.fichier_err=None
526 import Extensions.jdc_include
527 self.JdC_aux=Extensions.jdc_include.JdC_include
530 self.fichier_err="Le fichier INCLUDE n est pas defini"
531 self.parent.record_unit(unite,self)
532 raise Exception(self.fichier_err)
535 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
536 self.parent.record_unit(unite,self)
538 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
540 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
541 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
543 self.parent.record_unit(unite,self)
545 self.fichier_err = string.join(l)
546 self.contexte_fichier_init={}
550 # Si le fichier est deja defini on ne reevalue pas le fichier
551 # et on leve une exception si une erreur a été enregistrée
552 self.update_fichier_init(unite)
553 self.fichier_unite=unite
554 if self.fichier_err is not None: raise Exception(self.fichier_err)
557 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
558 def make_contexte(self,fichier,text):
560 Cette méthode sert à créer un contexte pour INCLUDE_MATERIAU
561 en interprétant un texte source Python
562 Elle est appelee par la fonction sd_prd d'INCLUDE_MATERIAU
564 # On supprime l'attribut mat qui bloque l'evaluation du source de l'INCLUDE_MATERIAU
565 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
566 if hasattr(self,'mat'):del self.mat
567 self.fichier_ini =fichier
568 self.fichier_unite =fichier
569 self.fichier_text=text
570 self.fichier_err=None
571 self.contexte_fichier_init={}
572 # On specifie la classe a utiliser pour le JDC auxiliaire
573 import Extensions.jdc_include
574 self.JdC_aux=Extensions.jdc_include.JdC_include
576 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
577 self.parent.record_unit(self.fichier_unite,self)
579 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
580 self.fichier_err = string.join(l)
581 self.parent.record_unit(self.fichier_unite,self)
583 self.contexte_fichier_init={}
586 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
587 def update_sdprod(self,cr='non'):
588 # Cette methode peut etre appelee dans EFICAS avec des mots cles de
589 # la commande modifies. Ceci peut conduire a la construction ou
590 # a la reconstruction d'etapes dans le cas d'INCLUDE ou d'INCLUDE_MATERIAU
591 # Il faut donc positionner le current_step avant l'appel
592 CONTEXT.unset_current_step()
593 CONTEXT.set_current_step(self)
594 valid=Validation.V_MACRO_ETAPE.MACRO_ETAPE.update_sdprod(self,cr=cr)
595 CONTEXT.unset_current_step()