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 # ======================================================================
27 # Objet re pour controler les identificateurs Python
28 concept_re=re.compile(r'[a-zA-Z_]\w*$')
30 # import rajoutés suite à l'ajout de Build_sd --> à résorber
33 from Noyau import N_Exception
34 from Noyau.N_Exception import AsException
35 # fin import à résorber
40 class ETAPE(I_MCCOMPO.MCCOMPO):
46 if CONTEXT.debug : print "SDNAME ",self.reuse,self.sd,self.sd.get_name()
48 if self.reuse != None:
49 sdname= self.reuse.get_name()
51 if self.sd:sdname=self.sd.get_name()
52 if string.find(sdname,'sansnom') != -1 or string.find(sdname,'SD_') != -1:
53 # dans le cas où la SD est 'sansnom' ou 'SD_' on retourne la chaîne vide
57 def is_reentrant(self):
59 Indique si la commande est reentrante
61 return self.definition.reentrant == 'o'
65 Met l'état de l'étape à : modifié
66 Propage la modification au parent
69 # doit etre realisée apres init_modif et la validite reevaluée
70 # apres cette action. L'état modified de tous les objets doit etre
72 self.state = 'modified'
74 self.parent.init_modif()
78 Méthode appelée une fois qu'une modification a été faite afin de
79 déclencher d'éventuels traitements post-modification
80 ex : INCLUDE et POURSUITE
83 d=self.parent.get_contexte_apres(self)
85 self.parent.fin_modif()
87 def nomme_sd(self,nom) :
89 Cette méthode a pour fonction de donner un nom (nom) au concept
90 produit par l'étape (self).
91 - si le concept n'existe pas, on essaye de le créer (à condition que l'étape soit valide ET non réentrante)
92 - si il existe déjà, on le renomme et on répercute les changements dans les autres étapes
93 Les valeurs de retour sont :
94 - 0 si le nommage n'a pas pu etre mené à son terme,
95 - 1 dans le cas contraire
97 # Le nom d'un concept doit etre un identificateur Python (toujours vrai ?)
98 if not concept_re.match(nom):
99 return 0,"Un nom de concept doit etre un identificateur Python"
101 if len(nom) > 8 and self.jdc.definition.code == 'ASTER':
102 return 0,"Nom de concept trop long (maxi 8 caractères)"
106 # On verifie d'abord si les mots cles sont valides
108 if not self.isvalid(sd='non') : return 0,"Nommage du concept refusé : l'opérateur n'est pas valide"
110 # Cas particulier des opérateurs obligatoirement réentrants
112 if self.definition.reentrant == 'o':
113 self.sd = self.reuse = self.jdc.get_sd_avant_etape(nom,self)
115 self.sdnom=self.sd.nom
116 return 1,"Concept existant"
118 return 0,"Opérateur réentrant mais concept non existant"
120 # Cas particulier des opérateurs facultativement réentrants
123 if self.definition.reentrant == 'f' :
124 sd = self.jdc.get_sd_avant_etape(nom,self)
126 # FR : il faut tester que la sd trouvée est du bon type !!!!!!!!!!!!!!!!!
127 if isinstance(sd,self.get_type_produit()) :
128 self.sd = self.reuse = sd
130 return 1,"Opérateur facultativement réentrant et concept existant trouvé"
132 return 0,"Concept déjà existant et de mauvais type"
134 # il faut enlever le lien vers une SD existante car si on passe ici
135 # cela signifie que l'opérateur n'est pas utilisé en mode réentrant.
136 # Si on ne fait pas cela, on risque de modifier une SD produite par un autre opérateur
139 self.sd = self.reuse = self.sdnom = None
141 # On est dans le cas ou l'opérateur n'est pas réentrant ou est facultativement reentrant
142 # mais est utilisé en mode non réentrant
145 if self.parent.get_sd_autour_etape(nom,self):
146 # Un concept de ce nom existe dans le voisinage de l'etape courante
147 # On retablit l'ancien concept reentrant s'il existait
149 self.sd=self.reuse=old_reuse
150 self.sdnom=old_reuse.nom
151 return 0,"Nommage du concept refuse : un concept de meme nom existe deja"
153 # Il n'existe pas de concept de ce nom dans le voisinage de l'etape courante
154 # On peut donc créer le concept retourné.
155 # Il est créé sans nom mais enregistré dans la liste des concepts existants
157 # Il suffit de changer son attribut nom pour le nommer
160 return 1,"Nommage du concept effectué"
163 if string.find(old_nom,'sansnom') :
164 # Dans le cas où old_nom == sansnom, isvalid retourne 0 alors que ...
165 # par contre si le concept existe et qu'il s'appelle sansnom c'est que l'étape est valide
166 # on peut donc le nommer sans test préalable
167 if self.parent.get_sd_autour_etape(nom,self):
168 return 0,"Nommage du concept refuse : un concept de meme nom existe deja"
172 return 1,"Nommage du concept effectué"
174 # Normalement l appel de isvalid a mis a jour le concept produit (son type)
175 # Il suffit de spécifier l attribut nom de sd pour le nommer si le nom n est pas
177 if self.parent.get_sd_autour_etape(nom,self):
178 return 0,"Nommage du concept refuse : un concept de meme nom existe deja"
182 return 1,"Nommage du concept effectué"
184 # Normalement on ne devrait pas passer ici
185 return 0,'Normalement on ne devrait pas passer ici'
187 def get_sdprods(self,nom_sd):
189 Fonction : retourne le concept produit par l etape de nom nom_sd
190 s il existe sinon None
193 if self.sd.nom == nom_sd:return self.sd
197 Rend l'etape courante active.
198 Il faut ajouter la sd si elle existe au contexte global du JDC
203 if not self.sd : return
205 self.jdc.append_sdprod(self.sd)
211 Rend l'etape courante inactive
212 Il faut supprimer la sd du contexte global du JDC
213 et de la liste des sd
216 if not self.sd : return
217 self.jdc.del_sdprod(self.sd)
218 self.jdc.delete_concept_after_etape(self,self.sd)
220 def control_sdprods(self,d):
222 Cette methode doit updater le contexte fournit par
223 l'appelant en argument (d) en fonction de sa definition
224 tout en verifiant que ses concepts produits ne sont pas
225 deja definis dans le contexte
227 if type(self.definition.op_init) == types.FunctionType:
228 apply(self.definition.op_init,(self,d))
230 if d.has_key(self.sd.nom):
231 # Le concept est deja defini
232 if self.reuse and self.reuse is d[self.sd.nom]:
233 # Le concept est reutilise : situation normale
236 # Redefinition du concept, on l'annule
237 #XXX on pourrait simplement annuler son nom pour conserver les objets
238 # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
239 self.sd=self.reuse=self.sdnom=None
242 # Le concept n'est pas defini, on peut updater d
243 d[self.sd.nom]=self.sd
245 def supprime_sdprods(self):
248 Lors d'une destruction d'etape, detruit tous les concepts produits
249 Un opérateur n a qu un concept produit
250 Une procedure n'en a aucun
251 Une macro en a en général plus d'un
253 if not self.is_reentrant() :
254 # l'étape n'est pas réentrante
255 # le concept retourné par l'étape est à supprimer car il était
258 self.parent.del_sdprod(self.sd)
259 self.parent.delete_concept(self.sd)
261 def delete_concept(self,sd):
266 Mettre a jour les mots cles de l etape et eventuellement
267 le concept produit si reuse
268 suite à la disparition du concept sd
269 Seuls les mots cles simples MCSIMP font un traitement autre
270 que de transmettre aux fils
272 if self.reuse and self.reuse == sd:
273 self.sd=self.reuse=None
275 for child in self.mc_liste :
276 child.delete_concept(sd)
278 def replace_concept(self,old_sd,sd):
281 - old_sd=concept remplace
282 - sd = nouveau concept
284 Mettre a jour les mots cles de l etape et eventuellement
285 le concept produit si reuse
286 suite au remplacement du concept old_sd
288 if self.reuse and self.reuse == old_sd:
289 self.sd=self.reuse=sd
291 for child in self.mc_liste :
292 child.replace_concept(old_sd,sd)
294 #ATTENTION SURCHARGE: cette methode doit etre gardée en synchronisation avec Noyau
295 def make_register(self):
297 Initialise les attributs jdc, id, niveau et réalise les
298 enregistrements nécessaires
299 Pour EFICAS, on tient compte des niveaux
300 Surcharge la methode make_register du package Noyau
303 self.jdc = self.parent.get_jdc_root()
304 self.id= self.parent.register(self)
305 if self.definition.niveau :
306 # La définition est dans un niveau. En plus on
307 # l'enregistre dans le niveau
308 self.nom_niveau_definition = self.definition.niveau.nom
309 self.niveau = self.parent.dict_niveaux[self.nom_niveau_definition]
310 self.niveau.register(self)
312 # La définition est au niveau global
313 self.nom_niveau_definition = 'JDC'
314 self.niveau=self.parent
316 self.jdc = self.parent =None
321 """ Méthode qui retourne une copie de self non enregistrée auprès du JDC
326 etape.state = 'modified'
331 for objet in self.mc_liste:
332 new_obj = objet.copy()
333 new_obj.reparent(etape)
334 etape.mc_liste.append(new_obj)
337 def get_noms_sd_oper_reentrant(self):
339 Retourne la liste des noms de concepts utilisés à l'intérieur de la commande
340 qui sont du type que peut retourner cette commande
342 liste_sd = self.get_sd_utilisees()
344 if type(self.definition.sd_prod) == types.FunctionType:
345 d=self.cree_dict_valeurs(self.mc_liste)
347 classe_sd_prod = apply(self.definition.sd_prod,(),d)
351 classe_sd_prod = self.definition.sd_prod
353 if sd.__class__ is classe_sd_prod : l_noms.append(sd.nom)
357 def get_sd_utilisees(self):
359 Retourne la liste des concepts qui sont utilisés à l'intérieur d'une commande
360 ( comme valorisation d'un MCS)
363 for child in self.mc_liste:
364 l.extend(child.get_sd_utilisees())
367 def get_genealogie(self):
369 Retourne la liste des noms des ascendants de l'objet self
370 en s'arretant à la première ETAPE rencontrée
374 def reparent(self,parent):
376 Cette methode sert a reinitialiser la parente de l'objet
379 self.jdc=parent.get_jdc_root()
381 for mocle in self.mc_liste:
384 def verif_existence_sd(self):
386 Vérifie que les structures de données utilisées dans self existent bien dans le contexte
387 avant étape, sinon enlève la référence à ces concepts
389 for motcle in self.mc_liste :
390 motcle.verif_existence_sd()
392 #ATTENTION SURCHARGE: a garder en synchro ou a reintegrer dans le Noyau
393 def Build_sd(self,nom):
395 Methode de Noyau surchargee pour poursuivre malgre tout
396 si une erreur se produit pendant la creation du concept produit
399 sd=Noyau.N_ETAPE.ETAPE.Build_sd(self,nom)
400 self.state="modified"
401 except AsException,e:
402 # Une erreur s'est produite lors de la construction du concept
403 # Comme on est dans EFICAS, on essaie de poursuivre quand meme
404 # Si on poursuit, on a le choix entre deux possibilités :
405 # 1. on annule la sd associée à self
406 # 2. on la conserve mais il faut la retourner
407 # En plus il faut rendre coherents sdnom et sd.nom
410 self.state="unchanged"
415 def Build_sd_old(self,nom):
417 Construit le concept produit de l'opérateur. Deux cas
418 peuvent se présenter :
420 - le parent n'est pas défini. Dans ce cas, l'étape prend en charge la création
421 et le nommage du concept.
423 - le parent est défini. Dans ce cas, l'étape demande au parent la création et
424 le nommage du concept.
427 if not self.isactif():return
428 # FR : attention cette méthode ne devrait pas se trouver là car elle surcharge celle qui
429 # se trouve dans N_ETAPE.py et elle est partie intégrante du noyau, mais, suite à l'absence de
430 # test de validité de l'opérateur avant d'essayer de déterminer la sd produite, on n'arrivait
431 # pas à relire avec EFICAS un fichier contenant une étape encore incomplète du style :
432 # sansnom = AFFE_CHAR_CINE(MODELE=None)
433 # Suite à la stabilisation du noyau d'Aster, je n'ai pas eu d'autre solution que de surcharger
434 # cette méthode ici en rajoutant le test manquant ...
435 # CCAR : cette modification ne corrige le probleme qu'en partie. Il faudrait probablement
436 # supprimer les erreurs fatales (exception ) et retourner systematiquement un objet produit
437 # meme en cas d'erreur et reporter l'emission du message d'erreur a la phase de validation
439 if not self.isvalid(sd='non') : return
443 sd= self.parent.create_sdprod(self,nom)
444 if type(self.definition.op_init) == types.FunctionType:
445 apply(self.definition.op_init,(self,self.parent.g_context))
447 sd=self.get_sd_prod()
448 # On n'utilise pas self.definition.op_init car self.parent
450 if sd != None and self.reuse == None:
451 # On ne nomme le concept que dans le cas de non reutilisation
454 if self.jdc and self.jdc.par_lot == "NON" :
457 except AsException,e:
458 # Une erreur s'est produite lors de la construction du concept
459 # Comme on est dans EFICAS, on essaie de poursuivre quand meme
460 # Si on poursuit, on a le choix entre deux possibilités :
461 # 1. on annule la sd associée à self
462 # 2. on la conserve mais il faut la retourner
463 # En plus il faut rendre coherents sdnom et sd.nom
466 self.state="unchanged"
470 #raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
471 # 'fichier : ',self.appel[1],e)
473 # XXX Normalement le contexte courant doit etre le parent.
474 # Il n'y a pas de raison de remettre le contexte au parent
475 #self.reset_current_step()
478 l=traceback.format_exception(sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2])
479 raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
480 'fichier : ',self.appel[1]+'\n',