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={}
43 """ Méthode qui retourne une copie de self non enregistrée auprès du JDC
45 On surcharge la methode de ETAPE pour exprimer que les concepts crees
46 par la MACRO d'origine ne sont pas crees par la copie mais eventuellement
49 etape=I_ETAPE.ETAPE.copy(self)
53 def get_sdprods(self,nom_sd):
55 Fonction : retourne le concept produit par l etape de nom nom_sd
56 s il existe sinon None
58 if self.sd and self.sd.nom == nom_sd :return self.sd
59 for co in self.sdprods:
60 if co.nom == nom_sd:return co
61 if type(self.definition.op_init) == types.FunctionType:
63 apply(self.definition.op_init,(self,d))
64 return d.get(nom_sd,None)
67 def get_contexte_jdc(self,fichier,text):
69 Interprète text comme un texte de jdc et retourne le
71 cad le dictionnaire des sd disponibles à la dernière étape
72 Si text n'est pas un texte de jdc valide, retourne None
74 --> utilisée par ops.POURSUITE et INCLUDE
77 # on essaie de créer un objet JDC auxiliaire avec un contexte initial
78 context_ini = self.parent.get_contexte_avant(self)
80 # Indispensable avant de creer un nouveau JDC
81 CONTEXT.unset_current_step()
84 if hasattr(self,'prefix'):
85 prefix_include=self.prefix
86 # ATTENTION : le dictionnaire recorded_units sert à memoriser les unites des
87 # fichiers inclus. Il est preferable de garder le meme dictionnaire pendant
88 # tout le traitement et de ne pas le reinitialiser brutalement (utiliser clear plutot)
89 # si on ne veut pas perdre la memoire des unites.
90 # En principe si la memorisation est faite au bon moment il n'est pas necessaire
91 # de prendre cette precaution mais ce n'est pas vrai partout.
92 old_recorded_units=self.recorded_units.copy()
93 self.recorded_units.clear()
95 j=self.JdC_aux( procedure=text,cata=self.jdc.cata,
97 context_ini = context_ini,
99 jdc_pere=self.jdc,etape_include=self,
100 prefix_include=prefix_include,
101 recorded_units=self.recorded_units,
102 old_recorded_units=old_recorded_units,**args)
105 # On récupère les étapes internes (pour validation)
108 traceback.print_exc()
109 # On force le contexte (etape courante) à self
110 CONTEXT.unset_current_step()
111 CONTEXT.set_current_step(self)
114 if not j.cr.estvide():
115 # Erreurs dans l'INCLUDE. On garde la memoire du fichier mais on n'insere pas les concepts
116 # On force le contexte (etape courante) à self
117 CONTEXT.unset_current_step()
118 CONTEXT.set_current_step(self)
119 raise Exception("Impossible de relire le fichier\n"+str(j.cr))
123 # On force le contexte (etape courante) à self
124 CONTEXT.unset_current_step()
125 CONTEXT.set_current_step(self)
126 raise Exception("Le fichier include contient des erreurs\n"+str(j.cr))
128 # On recupere le contexte apres la derniere etape
129 j_context=j.get_contexte_avant(None)
131 # Cette verification n'est plus necessaire elle est integree dans le JDC_INCLUDE
132 self.verif_contexte(j_context)
134 # On remplit le dictionnaire des concepts produits inclus
135 # en retirant les concepts présents dans le contexte initial
136 # On ajoute egalement le concept produit dans le sds_dict du parent
137 # sans verification car on est sur (verification integrée) que 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
149 # XXX j.supprime() ???
150 # On rétablit le contexte (etape courante) à self
151 CONTEXT.unset_current_step()
152 CONTEXT.set_current_step(self)
156 def verif_contexte(self,context):
158 On verifie que le contexte context peut etre inséré dans le jeu
159 de commandes à la position de self
161 for nom_sd,sd in context.items():
162 if not isinstance(sd,ASSD):continue
163 #if self.parent.get_sd_apres_etape(nom_sd,etape=self):
164 if self.parent.get_sd_apres_etape_avec_detruire(nom_sd,sd,etape=self):
165 # Il existe un concept produit par une etape apres self => impossible d'inserer
166 # On force le contexte (etape courante) à self
167 CONTEXT.unset_current_step()
168 CONTEXT.set_current_step(self)
169 raise Exception("Impossible d'inclure le fichier. Un concept de nom " +
170 "%s existe déjà dans le jeu de commandes." % nom_sd)
172 def reevalue_sd_jdc(self):
174 Avec la liste des SD qui ont été supprimées, propage la
175 disparition de ces SD dans toutes les étapes et descendants
177 l_sd_supp,l_sd_repl = self.diff_contextes()
179 self.parent.delete_concept_after_etape(self,sd)
180 for old_sd,sd in l_sd_repl:
181 self.parent.replace_concept_after_etape(self,old_sd,sd)
183 def diff_contextes(self):
185 Réalise la différence entre les 2 contextes
186 old_contexte_fichier_init et contexte_fichier_init
187 cad retourne la liste des sd qui ont disparu ou ne derivent pas de la meme classe
188 et des sd qui ont ete remplacees
190 if not hasattr(self,'old_contexte_fichier_init'):return [],[]
193 for old_key in self.old_contexte_fichier_init.keys():
194 if not self.contexte_fichier_init.has_key(old_key):
195 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
196 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
198 if isinstance(self.old_contexte_fichier_init[old_key],ASSD):
199 # Un concept de meme nom existe
200 old_class=self.old_contexte_fichier_init[old_key].__class__
201 if not isinstance(self.contexte_fichier_init[old_key],old_class):
202 # S'il n'est pas d'une classe derivee, on le supprime
203 l_sd_suppressed.append(self.old_contexte_fichier_init[old_key])
205 l_sd_replaced.append((self.old_contexte_fichier_init[old_key],self.contexte_fichier_init[old_key]))
206 return l_sd_suppressed,l_sd_replaced
208 def control_sdprods(self,d):
210 Cette methode doit updater le contexte fournit par
211 l'appelant en argument (d) en fonction de sa definition
212 tout en verifiant que ses concepts produits ne sont pas
213 deja definis dans le contexte
215 if hasattr(self,"fichier_unite"):
216 self.update_fichier_init(self.fichier_unite)
219 if type(self.definition.op_init) == types.FunctionType:
220 apply(self.definition.op_init,(self,d))
222 if d.has_key(self.sd.nom):
223 # Le concept est deja defini
224 if self.reuse and self.reuse is d[self.sd.nom]:
225 # Le concept est reutilise : situation normale
228 # Redefinition du concept, on l'annule
229 #XXX on pourrait simplement annuler son nom pour conserver les objets
230 # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
231 self.sd=self.reuse=self.sdnom=None
234 # Le concept n'est pas defini, on peut updater d
235 d[self.sd.nom]=self.sd
236 # On verifie les concepts a droite du signe =
237 for co in self.sdprods:
238 if d.has_key(co.nom) and co is not d[co.nom] :
239 self.delete_concept(co)
244 def supprime_sdprods(self):
247 Lors d'une destruction d'etape, detruit tous les concepts produits
248 Un opérateur n a qu un concept produit
249 Une procedure n'en a aucun
250 Une macro en a en général plus d'un
252 if not self.is_reentrant() :
253 # l'étape n'est pas réentrante
254 # le concept retourné par l'étape est à supprimer car il était
257 self.parent.del_sdprod(self.sd)
258 self.parent.delete_concept(self.sd)
259 # On détruit les concepts à droite du signe =
260 for co in self.sdprods:
261 self.parent.del_sdprod(co)
262 self.parent.delete_concept(co)
263 # Si la macro a des etapes et des concepts inclus, on les detruit
264 for nom_sd,co in self.g_context.items():
265 if not isinstance(co,ASSD):continue
266 self.parent.del_sdprod(co)
267 self.parent.delete_concept(co)
268 # On met g_context à blanc
271 #ATTENTION SURCHARGE: a garder en synchro ou a reintegrer dans le Noyau
272 def Build_sd(self,nom):
274 Methode de Noyau surchargee pour poursuivre malgre tout
275 si une erreur se produit pendant la creation du concept produit
278 sd=Noyau.N_MACRO_ETAPE.MACRO_ETAPE.Build_sd(self,nom)
279 self.state="unchanged"
281 except AsException,e:
282 # Une erreur s'est produite lors de la construction du concept
283 # Comme on est dans EFICAS, on essaie de poursuivre quand meme
284 # Si on poursuit, on a le choix entre deux possibilités :
285 # 1. on annule la sd associée à self
286 # 2. on la conserve mais il faut la retourner
287 # On choisit de l'annuler
288 # En plus il faut rendre coherents sdnom et sd.nom
291 self.state="unchanged"
296 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro ou a reintegrer)
297 def Build_sd_old(self,nom):
299 Construit le concept produit de l'opérateur. Deux cas
300 peuvent se présenter :
302 - le parent n'est pas défini. Dans ce cas, l'étape prend en charge
303 la création et le nommage du concept.
305 - le parent est défini. Dans ce cas, l'étape demande au parent la
306 création et le nommage du concept.
309 if not self.isactif():return
310 # CCAR : meme modification que dans I_ETAPE
311 if not self.isvalid(sd='non') : return
314 # On positionne la macro self en tant que current_step pour que les
315 # étapes créées lors de l'appel à sd_prod et à op_init aient la macro
317 self.set_current_step()
319 sd= self.parent.create_sdprod(self,nom)
320 if type(self.definition.op_init) == types.FunctionType:
321 apply(self.definition.op_init,(self,self.parent.g_context))
323 sd=self.get_sd_prod()
324 if sd != None and self.reuse == None:
325 # On ne nomme le concept que dans le cas de non reutilisation
328 self.reset_current_step()
329 # Si on est arrive ici, l'etape est valide
330 self.state="unchanged"
332 if self.jdc and self.jdc.par_lot == "NON" :
335 except AsException,e:
336 self.reset_current_step()
337 # Une erreur s'est produite lors de la construction du concept
338 # Comme on est dans EFICAS, on essaie de poursuivre quand meme
339 # Si on poursuit, on a le choix entre deux possibilités :
340 # 1. on annule la sd associée à self
341 # 2. on la conserve mais il faut qu'elle soit correcte et la retourner
342 # En plus il faut rendre coherents sdnom et sd.nom
343 # On choisit de retourner None et de mettre l'etape invalide
346 self.state="unchanged"
349 #raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
350 # 'fichier : ',self.appel[1],e)
354 self.reset_current_step()
355 l=traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2])
356 raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
357 'fichier : ',self.appel[1]+'\n',
360 def make_contexte_include(self,fichier,text):
362 Cette méthode sert à créer un contexte en interprétant un texte source
365 # on récupère le contexte d'un nouveau jdc dans lequel on interprete text
366 contexte = self.get_contexte_jdc(fichier,text)
367 if contexte == None :
368 raise Exception("Impossible de construire le jeu de commandes correspondant au fichier")
370 # Pour les macros de type include : INCLUDE, INCLUDE_MATERIAU et POURSUITE
371 # l'attribut g_context est un dictionnaire qui contient les concepts produits par inclusion
372 # l'attribut contexte_fichier_init est un dictionnaire qui contient les concepts produits
373 # en sortie de macro. g_context est obtenu en retirant de contexte_fichier_init les concepts
374 # existants en debut de macro contenus dans context_ini (dans get_contexte_jdc)
375 # g_context est utilisé pour avoir les concepts produits par la macro
376 # contexte_fichier_init est utilisé pour avoir les concepts supprimés par la macro
377 self.contexte_fichier_init = contexte
379 def reevalue_fichier_init(self):
380 """Recalcule les concepts produits par le fichier enregistre"""
381 old_context=self.contexte_fichier_init
383 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
385 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
386 self.fichier_err = string.join(l)
390 self.old_contexte_fichier_init=old_context
391 self.contexte_fichier_init={}
392 self.reevalue_sd_jdc()
395 # L'evaluation s'est bien passee
396 self.fichier_err = None
397 self.old_contexte_fichier_init=old_context
398 self.reevalue_sd_jdc()
400 def update_fichier_init(self,unite):
401 """Reevalue le fichier init sans demander (dans la mesure du possible) a l'utilisateur
402 les noms des fichiers
403 Ceci suppose que les relations entre unites et noms ont été memorisees préalablement
406 self.fichier_err=None
407 self.old_contexte_fichier_init=self.contexte_fichier_init
409 if unite != self.fichier_unite or not self.parent.recorded_units.has_key(unite):
410 # Changement d'unite ou Nouvelle unite
411 f,text=self.get_file(unite=unite,fic_origine=self.parent.nom)
415 self.fichier_text=text
416 self.recorded_units=units
417 if self.fichier_ini is None and self.jdc.appli:
418 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
419 message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
421 # Meme unite existante
422 f,text,units=self.parent.recorded_units[unite]
424 self.fichier_text=text
425 self.recorded_units=units
427 if self.fichier_ini is None:
428 # Le fichier n'est pas défini
429 self.fichier_err="Le fichier associé n'est pas défini"
430 self.parent.change_unit(unite,self,self.fichier_unite)
432 self.contexte_fichier_init={}
433 self.parent.reset_context()
434 self.reevalue_sd_jdc()
438 self.make_contexte_include(self.fichier_ini,self.fichier_text)
439 # Les 3 attributs fichier_ini fichier_text recorded_units doivent etre corrects
440 # avant d'appeler change_unit
441 self.parent.change_unit(unite,self,self.fichier_unite)
443 # Erreurs lors de l'evaluation de text dans un JDC auxiliaire
444 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
445 # On conserve la memoire du nouveau fichier
446 # mais on n'utilise pas les concepts crees par ce fichier
447 # on met l'etape en erreur : fichier_err=string.join(l)
448 self.fichier_err=string.join(l)
449 self.parent.change_unit(unite,self,self.fichier_unite)
451 self.contexte_fichier_init={}
453 # Le contexte du parent doit etre reinitialise car les concepts produits ont changé
454 self.parent.reset_context()
455 # Si des concepts ont disparu lors du changement de fichier, on demande leur suppression
456 self.reevalue_sd_jdc()
458 def record_unite(self):
459 if self.nom == "POURSUITE":
460 self.parent.record_unit(None,self)
462 if hasattr(self,'fichier_unite') :
463 self.parent.record_unit(self.fichier_unite,self)
465 def make_poursuite(self):
466 """ Cette methode est appelée par la fonction sd_prod de la macro POURSUITE
468 if not hasattr(self,'fichier_ini') :
469 # Si le fichier n'est pas defini on le demande
470 f,text=self.get_file_memo(fic_origine=self.parent.nom)
471 # On memorise le fichier retourne
473 self.fichier_unite = None
474 self.fichier_text = text
475 self.fichier_err=None
476 import Extensions.jdc_include
477 self.JdC_aux=Extensions.jdc_include.JdC_poursuite
478 self.contexte_fichier_init={}
481 self.fichier_err="Le fichier POURSUITE n'est pas defini"
482 self.parent.record_unit(None,self)
483 raise Exception(self.fichier_err)
486 self.make_contexte_include(self.fichier_ini,self.fichier_text)
487 self.parent.record_unit(None,self)
489 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
491 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier poursuite",
492 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
494 self.parent.record_unit(None,self)
496 self.fichier_err = string.join(l)
497 self.contexte_fichier_init={}
501 # Si le fichier est deja defini on ne reevalue pas le fichier
502 # et on leve une exception si une erreur a été enregistrée
503 self.update_fichier_init(None)
504 if self.fichier_err is not None: raise Exception(self.fichier_err)
506 def get_file(self,unite=None,fic_origine=''):
507 """Retourne le nom du fichier et le source correspondant a l'unite unite
508 Initialise en plus recorded_units
512 f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
515 self.recorded_units=units
518 def get_file_memo(self,unite=None,fic_origine=''):
519 """Retourne le nom du fichier et le source correspondant a l'unite unite
520 Initialise en plus recorded_units
523 if self.parent.old_recorded_units.has_key(unite):
524 f,text,units=self.parent.old_recorded_units[unite]
525 self.recorded_units=units
528 f,text=self.jdc.get_file(unite=unite,fic_origine=fic_origine)
531 self.recorded_units=units
532 if f is None and self.jdc.appli:
533 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
534 message="Ce fichier ne sera pas pris en compte\n"+"Le fichier associé n'est pas défini")
537 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
538 def make_include(self,unite=None):
540 Inclut un fichier dont l'unite logique est unite
541 Cette methode est appelee par la fonction sd_prod de la macro INCLUDE
542 Si l'INCLUDE est invalide, la methode doit produire une exception
543 Sinon on retourne None. Les concepts produits par l'INCLUDE sont
544 pris en compte par le JDC parent lors du calcul du contexte (appel de ???)
547 # On supprime l'attribut unite qui bloque l'evaluation du source de l'INCLUDE
548 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
550 # Si unite n'a pas de valeur, l'etape est forcement invalide. On peut retourner None
551 if not unite : return
553 if not hasattr(self,'fichier_ini') :
554 # Si le fichier n'est pas defini on le demande
555 f,text=self.get_file_memo(unite=unite,fic_origine=self.parent.nom)
556 # On memorise le fichier retourne
558 self.fichier_text = text
559 self.contexte_fichier_init={}
560 self.fichier_unite=unite
561 self.fichier_err=None
562 import Extensions.jdc_include
563 self.JdC_aux=Extensions.jdc_include.JdC_include
566 self.fichier_err="Le fichier INCLUDE n est pas defini"
567 self.parent.record_unit(unite,self)
568 raise Exception(self.fichier_err)
571 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
572 self.parent.record_unit(unite,self)
574 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
576 self.jdc.appli.affiche_alerte("Erreur lors de l'evaluation du fichier inclus",
577 message="Ce fichier ne sera pas pris en compte\n"+string.join(l)
579 self.parent.record_unit(unite,self)
581 self.fichier_err = string.join(l)
582 self.contexte_fichier_init={}
586 # Si le fichier est deja defini on ne reevalue pas le fichier
587 # et on leve une exception si une erreur a été enregistrée
588 self.update_fichier_init(unite)
589 self.fichier_unite=unite
590 if self.fichier_err is not None: raise Exception(self.fichier_err)
593 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
594 def make_contexte(self,fichier,text):
596 Cette méthode sert à créer un contexte pour INCLUDE_MATERIAU
597 en interprétant un texte source Python
598 Elle est appelee par la fonction sd_prd d'INCLUDE_MATERIAU
600 # On supprime l'attribut mat qui bloque l'evaluation du source de l'INCLUDE_MATERIAU
601 # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini
602 if hasattr(self,'mat'):del self.mat
603 self.fichier_ini =fichier
604 self.fichier_unite =fichier
605 self.fichier_text=text
606 self.fichier_err=None
607 self.contexte_fichier_init={}
608 # On specifie la classe a utiliser pour le JDC auxiliaire
609 import Extensions.jdc_include
610 self.JdC_aux=Extensions.jdc_include.JdC_include
612 self.make_contexte_include(self.fichier_ini ,self.fichier_text)
613 self.parent.record_unit(self.fichier_unite,self)
615 l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1])
616 self.fichier_err = string.join(l)
617 self.parent.record_unit(self.fichier_unite,self)
619 self.contexte_fichier_init={}
622 #ATTENTION : cette methode surcharge celle de Noyau (a garder en synchro)
623 def update_sdprod(self,cr='non'):
624 # Cette methode peut etre appelee dans EFICAS avec des mots cles de
625 # la commande modifies. Ceci peut conduire a la construction ou
626 # a la reconstruction d'etapes dans le cas d'INCLUDE ou d'INCLUDE_MATERIAU
627 # Il faut donc positionner le current_step avant l'appel
628 CONTEXT.unset_current_step()
629 CONTEXT.set_current_step(self)
630 valid=Validation.V_MACRO_ETAPE.MACRO_ETAPE.update_sdprod(self,cr=cr)
631 CONTEXT.unset_current_step()