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 # ======================================================================
28 # Objet re pour controler les identificateurs Python
29 concept_re=re.compile(r'[a-zA-Z_]\w*$')
31 # import rajoutés suite à l'ajout de Build_sd --> à résorber
34 from Noyau import N_Exception
35 from Noyau.N_Exception import AsException
36 # fin import à résorber
42 class ETAPE(I_MCCOMPO.MCCOMPO):
48 if CONTEXT.debug : print "SDNAME ",self.reuse,self.sd,self.sd.get_name()
50 if self.reuse != None:
51 sdname= self.reuse.get_name()
53 if self.sd:sdname=self.sd.get_name()
54 if string.find(sdname,'sansnom') != -1 or string.find(sdname,'SD_') != -1:
55 # dans le cas où la SD est 'sansnom' ou 'SD_' on retourne la chaîne vide
59 def is_reentrant(self):
61 Indique si la commande est reentrante
63 return self.definition.reentrant == 'o'
67 Met l'état de l'étape à : modifié
68 Propage la modification au parent
70 # init_modif doit etre appelé avant de réaliser une modification
71 # La validité devra etre recalculée apres cette modification
72 # mais dans l'appel à fin_modif pour préserver l'état modified
73 # de tous les objets entre temps
74 #print "init_modif",self,self.parent
75 self.state = 'modified'
77 self.parent.init_modif()
81 Méthode appelée une fois qu'une modification a été faite afin de
82 déclencher d'éventuels traitements post-modification
83 ex : INCLUDE et POURSUITE
85 #print "fin_modif",self,self.parent
86 #if hasattr(self,'jdc_aux'):print "fin_modif",self.jdc_aux.context_ini
88 #if hasattr(self,'jdc_aux'):print "fin_modif",self.jdc_aux.context_ini
89 d=self.parent.get_contexte_apres(self)
91 #if hasattr(self,'jdc_aux'):print "fin_modif",self.jdc_aux.context_ini
92 CONNECTOR.Emit(self,"valid")
94 self.parent.fin_modif()
96 def nomme_sd(self,nom) :
98 Cette méthode a pour fonction de donner un nom (nom) au concept
99 produit par l'étape (self).
100 - si le concept n'existe pas, on essaye de le créer (à condition que l'étape soit valide ET non réentrante)
101 - si il existe déjà, on le renomme et on répercute les changements dans les autres étapes
102 Les valeurs de retour sont :
103 - 0 si le nommage n'a pas pu etre mené à son terme,
104 - 1 dans le cas contraire
106 # Le nom d'un concept doit etre un identificateur Python (toujours vrai ?)
107 if not concept_re.match(nom):
108 return 0,"Un nom de concept doit etre un identificateur Python"
110 if len(nom) > 8 and self.jdc.definition.code == 'ASTER':
111 return 0,"Nom de concept trop long (maxi 8 caractères)"
115 # On verifie d'abord si les mots cles sont valides
117 if not self.isvalid(sd='non') : return 0,"Nommage du concept refusé : l'opérateur n'est pas valide"
119 # Cas particulier des opérateurs obligatoirement réentrants
121 if self.definition.reentrant == 'o':
122 self.sd = self.reuse = self.jdc.get_sd_avant_etape(nom,self)
124 self.sdnom=self.sd.nom
126 return 1,"Concept existant"
128 return 0,"Opérateur réentrant mais concept non existant"
130 # Cas particulier des opérateurs facultativement réentrants
133 if self.definition.reentrant == 'f' :
134 sd = self.jdc.get_sd_avant_etape(nom,self)
136 # FR : il faut tester que la sd trouvée est du bon type !!!!!!!!!!!!!!!!!
137 if isinstance(sd,self.get_type_produit()) :
138 self.sd = self.reuse = sd
141 return 1,"Opérateur facultativement réentrant et concept existant trouvé"
143 return 0,"Concept déjà existant et de mauvais type"
145 # il faut enlever le lien vers une SD existante car si on passe ici
146 # cela signifie que l'opérateur n'est pas utilisé en mode réentrant.
147 # Si on ne fait pas cela, on risque de modifier une SD produite par un autre opérateur
150 self.sd = self.reuse = self.sdnom = None
152 # On est dans le cas ou l'opérateur n'est pas réentrant ou est facultativement reentrant
153 # mais est utilisé en mode non réentrant
156 if self.parent.get_sd_autour_etape(nom,self):
157 # Un concept de ce nom existe dans le voisinage de l'etape courante
158 # On retablit l'ancien concept reentrant s'il existait
160 self.sd=self.reuse=old_reuse
161 self.sdnom=old_reuse.nom
162 return 0,"Nommage du concept refuse : un concept de meme nom existe deja"
164 # Il n'existe pas de concept de ce nom dans le voisinage de l'etape courante
165 # On peut donc créer le concept retourné.
166 # Il est créé sans nom mais enregistré dans la liste des concepts existants
169 # Il suffit de changer son attribut nom pour le nommer
173 return 1,"Nommage du concept effectué"
175 return 0,"Nommage impossible"+str(sys.exc_info()[1])
178 if string.find(old_nom,'sansnom') :
179 # Dans le cas où old_nom == sansnom, isvalid retourne 0 alors que ...
180 # par contre si le concept existe et qu'il s'appelle sansnom c'est que l'étape est valide
181 # on peut donc le nommer sans test préalable
182 if self.parent.get_sd_autour_etape(nom,self):
183 return 0,"Nommage du concept refuse : un concept de meme nom existe deja"
188 return 1,"Nommage du concept effectué"
190 # Normalement l appel de isvalid a mis a jour le concept produit (son type)
191 # Il suffit de spécifier l attribut nom de sd pour le nommer si le nom n est pas
193 if self.parent.get_sd_autour_etape(nom,self):
194 return 0,"Nommage du concept refuse : un concept de meme nom existe deja"
199 return 1,"Nommage du concept effectué"
201 # Normalement on ne devrait pas passer ici
202 return 0,'Normalement on ne devrait pas passer ici'
204 def get_sdprods(self,nom_sd):
206 Fonction : retourne le concept produit par l etape de nom nom_sd
207 s il existe sinon None
210 if self.sd.nom == nom_sd:return self.sd
214 Rend l'etape courante active.
215 Il faut ajouter la sd si elle existe au contexte global du JDC
222 self.jdc.append_sdprod(self.sd)
225 CONNECTOR.Emit(self,"add",None)
226 CONNECTOR.Emit(self,"valid")
230 Rend l'etape courante inactive
231 Il faut supprimer la sd du contexte global du JDC
232 et de la liste des sd
236 self.jdc.del_sdprod(self.sd)
237 self.jdc.delete_concept_after_etape(self,self.sd)
238 CONNECTOR.Emit(self,"supp",None)
239 CONNECTOR.Emit(self,"valid")
241 def control_sdprods(self,d):
243 Cette methode doit updater le contexte fournit par
244 l'appelant en argument (d) en fonction de sa definition
245 tout en verifiant que ses concepts produits ne sont pas
246 deja definis dans le contexte
248 if type(self.definition.op_init) == types.FunctionType:
250 apply(self.definition.op_init,(self,d))
252 #traceback.print_exc()
256 if d.has_key(self.sd.nom):
257 # Le concept est deja defini
258 if self.reuse and self.reuse is d[self.sd.nom]:
259 # Le concept est reutilise : situation normale
262 # Redefinition du concept, on l'annule
263 #XXX on pourrait simplement annuler son nom pour conserver les objets
264 # l'utilisateur n'aurait alors qu'a renommer le concept (faisable??)
265 self.sd=self.reuse=self.sdnom=None
268 # Le concept n'est pas defini, on peut updater d
269 d[self.sd.nom]=self.sd
271 def supprime_sdprod(self,sd):
273 Supprime le concept produit sd s'il est produit par l'etape
275 if sd is not self.sd:return
278 self.parent.del_sdprod(sd)
281 self.parent.delete_concept(sd)
283 def supprime_sdprods(self):
286 Lors d'une destruction d'etape, detruit tous les concepts produits
287 Un opérateur n a qu un concept produit
288 Une procedure n'en a aucun
289 Une macro en a en général plus d'un
291 #print "supprime_sdprods",self
292 if self.reuse is self.sd :return
293 # l'étape n'est pas réentrante
294 # le concept retourné par l'étape est à supprimer car il était
297 self.parent.del_sdprod(self.sd)
298 self.parent.delete_concept(self.sd)
303 def delete_concept(self,sd):
308 Mettre a jour les mots cles de l etape et eventuellement
309 le concept produit si reuse
310 suite à la disparition du concept sd
311 Seuls les mots cles simples MCSIMP font un traitement autre
312 que de transmettre aux fils
314 if self.reuse and self.reuse == sd:
315 self.sd=self.reuse=None
317 for child in self.mc_liste :
318 child.delete_concept(sd)
320 def replace_concept(self,old_sd,sd):
323 - old_sd=concept remplace
324 - sd = nouveau concept
326 Mettre a jour les mots cles de l etape et eventuellement
327 le concept produit si reuse
328 suite au remplacement du concept old_sd
330 if self.reuse and self.reuse == old_sd:
331 self.sd=self.reuse=sd
333 for child in self.mc_liste :
334 child.replace_concept(old_sd,sd)
336 def reset_context(self):
339 def get_noms_sd_oper_reentrant(self):
341 Retourne la liste des noms de concepts utilisés à l'intérieur de la commande
342 qui sont du type que peut retourner cette commande
344 liste_sd = self.get_sd_utilisees()
346 if type(self.definition.sd_prod) == types.FunctionType:
347 d=self.cree_dict_valeurs(self.mc_liste)
349 classe_sd_prod = apply(self.definition.sd_prod,(),d)
353 classe_sd_prod = self.definition.sd_prod
355 if sd.__class__ is classe_sd_prod : l_noms.append(sd.nom)
359 def get_genealogie(self):
361 Retourne la liste des noms des ascendants de l'objet self
362 en s'arretant à la première ETAPE rencontrée
366 def verif_existence_sd(self):
368 Vérifie que les structures de données utilisées dans self existent bien dans le contexte
369 avant étape, sinon enlève la référence à ces concepts
371 #print "verif_existence_sd",self.sd
372 for motcle in self.mc_liste :
373 motcle.verif_existence_sd()
375 #ATTENTION SURCHARGE: a garder en synchro ou a reintegrer dans le Noyau
376 def Build_sd(self,nom):
378 Methode de Noyau surchargee pour poursuivre malgre tout
379 si une erreur se produit pendant la creation du concept produit
382 sd=Noyau.N_ETAPE.ETAPE.Build_sd(self,nom)
383 except AsException,e:
384 # Une erreur s'est produite lors de la construction du concept
385 # Comme on est dans EFICAS, on essaie de poursuivre quand meme
386 # Si on poursuit, on a le choix entre deux possibilités :
387 # 1. on annule la sd associée à self
388 # 2. on la conserve mais il faut la retourner
389 # En plus il faut rendre coherents sdnom et sd.nom
392 self.state="unchanged"
397 #ATTENTION SURCHARGE: cette methode doit etre gardée en synchronisation avec Noyau
398 def make_register(self):
400 Initialise les attributs jdc, id, niveau et réalise les
401 enregistrements nécessaires
402 Pour EFICAS, on tient compte des niveaux
403 Surcharge la methode make_register du package Noyau
406 self.jdc = self.parent.get_jdc_root()
407 self.id= self.parent.register(self)
408 self.UserError=self.jdc.UserError
409 if self.definition.niveau :
410 # La définition est dans un niveau. En plus on
411 # l'enregistre dans le niveau
412 self.nom_niveau_definition = self.definition.niveau.nom
413 self.niveau = self.parent.dict_niveaux[self.nom_niveau_definition]
414 self.niveau.register(self)
416 # La définition est au niveau global
417 self.nom_niveau_definition = 'JDC'
418 self.niveau=self.parent
420 self.jdc = self.parent =None
423 self.UserError="UserError"