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 # ======================================================================
23 import types,traceback
24 import string,linecache
28 from Noyau.N_ASSD import ASSD
29 from Noyau.N_ETAPE import ETAPE
30 from Noyau.N_Exception import AsException
31 from Extensions import commentaire,parametre,parametre_eval
33 class JDC(I_OBJECT.OBJECT):
38 self.etapes_niveaux=[]
42 self._etape_context=None
44 def get_cmd(self,nomcmd):
46 Retourne l'objet de type COMMANDE de nom nomcmd
48 for cata in self.cata:
49 if hasattr(cata,nomcmd):
50 return getattr(cata,nomcmd)
52 def get_sd_avant_du_bon_type(self,etape,types_permis):
54 Retourne la liste des concepts avant etape d'un type acceptable
56 d=self.get_contexte_avant(etape)
59 if type(v) != types.InstanceType : continue
60 # On considère que seul assd indique un type quelconque pas CO
61 elif self.assd in types_permis :
63 elif self.est_permis(v,types_permis):
68 def est_permis(self,v,types_permis):
69 for type_ok in types_permis:
70 if type_ok in ('R','I','C','TXM') and v in self.params :
72 elif type_ok == 'R' and v.__class__.__name__ == 'reel' :
74 elif type_ok == 'I' and v.__class__.__name__ == 'entier' :
76 elif type_ok == 'C' and v.__class__.__name__ == 'complexe' :
78 elif type_ok == 'TXM' and v.__class__.__name__ == 'chaine' :
80 elif type(type_ok) != types.ClassType :
82 elif v.__class__ == type_ok or issubclass(v.__class__,type_ok):
86 def addentite(self,name,pos):
89 Si name est le nom d une commande ou un commentaire ajoute
91 Sinon remonte une erreur
95 if name == "COMMENTAIRE" :
96 # ajout d'un commentaire
97 self.set_current_step()
99 for child in self.etapes :
100 if isinstance(child,commentaire.COMMENTAIRE):
102 objet = commentaire.COMMENTAIRE('',parent=self)
103 objet.nom = "_comm_"+`ind`
104 if pos == None : pos = 0
105 self.etapes.insert(pos,objet)
109 elif name == "PARAMETRE":
110 # ajout d'un parametre
111 self.set_current_step()
112 nom_param = '_param_'+str(len(self.params)+1)
113 objet = parametre.PARAMETRE(nom=nom_param)
114 if pos == None : pos = 0
115 self.etapes.insert(pos,objet)
120 elif name == "PARAMETRE_EVAL":
121 # ajout d'un parametre EVAL
122 self.set_current_step()
123 nom_param = '_param_'+str(len(self.params)+1)
124 objet = parametre_eval.PARAMETRE_EVAL(nom=nom_param)
125 if pos == None : pos = 0
126 self.etapes.insert(pos,objet)
131 elif type(name)==types.InstanceType:
132 # on est dans le cas où on veut ajouter une commande déjà
133 # existante (par copie donc)
134 # on est donc nécessairement en mode editeur ...
136 # Il ne faut pas oublier de reaffecter le parent d'obj (si copie)
138 self.set_current_step()
139 if isinstance(objet,ETAPE):
140 if objet.nom_niveau_definition == 'JDC':
141 # l'objet dépend directement du JDC
144 # l'étape dépend d'un niveau et non directement du JDC :
145 # il faut l'enregistrer dans le niveau de parent
146 objet.parent.dict_niveaux[objet.nom_niveau_definition].register(objet)
147 objet.niveau = objet.parent.dict_niveaux[objet.nom_niveau_definition]
148 self.etapes.insert(pos,objet)
149 # il faut vérifier que les concepts utilisés par objet existent bien
150 # à ce niveau d'arborescence
151 objet.verif_existence_sd()
157 # On veut ajouter une nouvelle commande
159 self.set_current_step()
160 cmd=self.get_cmd(name)
161 # L'appel a make_objet n'a pas pour effet d'enregistrer l'étape
162 # auprès du step courant car editmode vaut 1
163 # Par contre elle a le bon parent grace a set_current_step
165 if pos == None : pos = 0
166 self.etapes.insert(pos,e)
167 self.reset_current_step()
173 traceback.print_exc()
174 self.reset_current_step()
176 raise AsException("Impossible d ajouter la commande "+name)
178 def set_current_step(self):
179 CONTEXT.unset_current_step()
180 CONTEXT.set_current_step(self)
182 def reset_current_step(self):
183 CONTEXT.unset_current_step()
185 def liste_mc_presents(self):
188 def get_sd_avant_etape(self,nom_sd,etape):
189 return self.get_contexte_avant(etape).get(nom_sd,None)
191 def get_sd_apres_etape(self,nom_sd,etape,avec='non'):
193 Cette méthode retourne la SD de nom nom_sd qui est éventuellement
195 Si avec vaut 'non' exclut etape de la recherche
197 ietap=self.etapes.index(etape)
198 if avec == 'non':ietap=ietap+1
199 for e in self.etapes[ietap:]:
200 sd=e.get_sdprods(nom_sd)
202 if hasattr(e,'reuse'):
207 def get_sd_autour_etape(self,nom_sd,etape,avec='non'):
209 Fonction: retourne la SD de nom nom_sd qui est éventuellement
210 définie avant ou apres etape
211 Permet de vérifier si un concept de meme nom existe dans le périmètre
213 Si avec vaut 'non' exclut etape de la recherche
215 sd=self.get_sd_avant_etape(nom_sd,etape)
217 return self.get_sd_apres_etape(nom_sd,etape,avec)
219 def get_contexte_avant(self,etape):
221 Retourne le dictionnaire des concepts connus avant etape
222 On tient compte des commandes qui modifient le contexte
223 comme DETRUIRE ou les macros
224 Si etape == None, on retourne le contexte en fin de JDC
226 # L'étape courante pour laquelle le contexte a été calculé est
227 # mémorisée dans self.index_etape_courante
228 # XXX on pourrait faire mieux dans le cas PAR_LOT="NON" : en
230 # courante pendant le processus de construction des étapes.
231 # Si on insère des commandes (par ex, dans EFICAS), il faut préalablement
232 # remettre ce pointeur à 0
234 index_etape=self.etapes.index(etape)
236 index_etape=len(self.etapes)
237 if index_etape >= self.index_etape_courante:
238 # On calcule le contexte en partant du contexte existant
239 d=self.current_context
240 if self.index_etape_courante==0 and self.context_ini:
241 d.update(self.context_ini)
242 liste_etapes=self.etapes[self.index_etape_courante:index_etape]
244 d=self.current_context={}
245 if self.context_ini:d.update(self.context_ini)
246 liste_etapes=self.etapes
248 for e in liste_etapes:
253 self.index_etape_courante=index_etape
256 def get_contexte_apres(self,etape):
258 Retourne le dictionnaire des concepts connus apres etape
259 On tient compte des commandes qui modifient le contexte
260 comme DETRUIRE ou les macros
261 Si etape == None, on retourne le contexte en fin de JDC
263 if not etape: return self.get_contexte_avant(etape)
265 d=self.get_contexte_avant(etape)
266 if etape.isactif():etape.update_context(d)
267 self.index_etape_courante=self.index_etape_courante+1
270 def active_etapes(self):
272 Cette méthode a pour fonction de désactiver les étapes qui doivent
273 l'être cad, dans le cas d'ASTER, les étapes qui ne sont pas
274 comprises entre le premier DEBUT/POURSUITE et le premier FIN
275 et rendre actives les autres
277 if self.definition.code == 'ASTER' :
278 # Seulement pour ASTER :
279 # Avant DEBUT actif vaut 0
280 # Apres DEBUT et avant le 1er FIN actif vaut 1
281 # Apres le 1er FIN actif vaut -1
285 for etape in self.etapes:
286 if actif == 0 and etape.nom in ['DEBUT','POURSUITE']:actif=1
291 if etape.nom == 'FIN':actif=-1
293 def suppentite(self,etape) :
295 Cette methode a pour fonction de supprimer une étape dans
299 # On memorise le contexte avant l'etape a supprimer
300 d=self.get_contexte_avant(etape)
301 index_etape=self.etapes.index(etape)
303 self.etapes.remove(etape)
304 if etape.niveau is not self:
305 # Dans ce cas l'étape est enregistrée dans un niveau
306 # Il faut la désenregistrer
307 etape.niveau.unregister(etape)
308 etape.supprime_sdprods()
311 # Apres suppression de l'etape il faut controler que les etapes
312 # suivantes ne produisent pas des concepts DETRUITS dans op_init de etape
313 for e in self.etapes[index_etape:]:
321 if not self.cr.estvide():return
325 def register(self,etape):
327 Cette méthode ajoute etape dans la liste
328 des etapes self.etapes et retourne l identificateur d'étape
329 fourni par l appel a g_register
330 A quoi sert editmode ?
331 - Si editmode vaut 1, on est en mode edition de JDC. On cherche
332 à enregistrer une étape que l'on a créée avec eficas (en passant
333 par addentite) auquel cas on ne veut récupérer que son numéro
334 d'enregistrement et c'est addentité qui l'enregistre dans
335 self.etapes à la bonne place...
336 - Si editmode vaut 0, on est en mode relecture d'un fichier de
337 commandes et on doit enregistrer l'étape à la fin de self.etapes
338 (dans ce cas l'ordre des étapes est bien l'ordre chronologique
341 if not self.editmode:
342 self.etapes.append(etape)
345 return self.g_register(etape)
347 def register_parametre(self,param):
349 Cette méthode sert à ajouter un paramètre dans la liste des paramètres
351 self.params.append(param)
353 def register_fonction(self,fonction):
355 Cette méthode sert à ajouter une fonction dans la liste des fonctions
357 self.fonctions.append(fonction)
359 def delete_param(self,param):
361 Supprime le paramètre param de la liste des paramètres
364 if param in self.params : self.params.remove(param)
365 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
367 def get_parametres_fonctions_avant_etape(self,etape):
369 Retourne deux éléments :
370 - une liste contenant les noms des paramètres (constantes ou EVAL)
372 - une liste contenant les formules définies avant etape
376 # on récupère le contexte avant etape
377 # on ne peut mettre dans les deux listes que des éléments de ce contexte
378 d=self.get_contexte_avant(etape)
379 # construction de l_constantes
380 for param in self.params:
382 if not nom : continue
383 if d.has_key(nom): l_constantes.append(nom)
384 # construction de l_fonctions
385 for form in self.fonctions:
387 if not nom : continue
388 if d.has_key(nom): l_fonctions.append(form.get_formule())
390 # on ajoute les concepts produits par DEFI_VALEUR
391 # XXX On pourrait peut etre faire plutot le test sur le type
392 # de concept : entier, reel, complexe, etc.
393 for k,v in d.items():
394 if hasattr(v,'etape') and v.etape.nom in ('DEFI_VALEUR',):
395 l_constantes.append(k)
397 # on retourne les deux listes
398 return l_constantes,l_fonctions
400 def get_nb_etapes_avant(self,niveau):
402 Retourne le nombre d etapes avant le debut de niveau
405 for niv in self.etapes_niveaux:
406 if niv == niveau:break
407 nb=nb+len(niv.etapes)
410 def send_message(self,message):
412 self.appli.send_message(message)
414 def init_modif(self):
416 Méthode appelée au moment où une modification va être faite afin de
417 déclencher d'éventuels traitements pré-modification
419 self.state = 'modified'
425 def get_liste_mc_inconnus(self):
427 Retourne une liste contenant les mots-clés inconnus à la relecture du JDC
429 # cette liste a le format suivant : [etape,(bloc,mcfact,...),nom_mc,valeur_mc]
431 for etape in self.etapes :
433 if not etape.isvalid() :
434 l = etape.get_liste_mc_inconnus()
435 if l : l_mc.extend(l)
438 def get_file(self,unite=None,fic_origine=''):
440 Retourne le nom du fichier correspondant à un numero d'unité
441 logique (entier) ainsi que le source contenu dans le fichier
444 # Si le JDC est relié à une application maitre, on délègue la recherche
445 file,text = self.appli.get_file(unite,fic_origine)
449 if os.path.exists("fort."+str(unite)):
450 file= "fort."+str(unite)
452 raise AsException("Impossible de trouver le fichier correspondant \
453 a l unite %s" % unite)
454 if not os.path.exists(file):
455 raise AsException("%s n'est pas un fichier existant" % unite)
459 if file == None : return None,None
460 text=string.replace(text,'\r\n','\n')
461 linecache.cache[file]=0,0,string.split(text,'\n'),file
465 def get_genealogie(self):
467 Retourne la liste des noms des ascendants de l'objet self
468 jusqu'à la première ETAPE parent.
472 def NommerSdprod(self,sd,sdnom,restrict='non'):
474 Nomme la SD apres avoir verifie que le nommage est possible :
476 Si le nom est deja utilise, leve une exception
477 Met le concept créé dans le concept global g_context
479 # XXX En mode editeur dans EFICAS, le nommage doit etre géré différemment
480 # Le dictionnaire g_context ne représente pas le contexte
481 # effectif avant une étape.
482 # Il faut utiliser get_contexte_avant avec indication de l'étape
484 # Cette etape est indiquee par l'attribut _etape_context qui a ete
485 # positionné préalablement par un appel à set_etape_context
487 if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom
489 if self._etape_context:
490 o=self.get_contexte_avant(self._etape_context).get(sdnom,None)
492 o=self.sds_dict.get(sdnom,None)
494 if isinstance(o,ASSD):
495 raise AsException("Nom de concept deja defini : %s" % sdnom)
497 # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
498 # Ajoute a la creation (appel de reg_sd).
499 self.sds_dict[sdnom]=sd
502 def set_etape_context(self,etape):
504 Positionne l'etape qui sera utilisee dans NommerSdProd pour
505 decider si le concept passé pourra etre nommé
507 self._etape_context=etape
509 def reset_context(self):
511 Cette methode reinitialise le contexte glissant pour pouvoir
512 tenir compte des modifications de l'utilisateur : création
513 de commandes, nommage de concepts, etc.
515 self.current_context={}
516 self.index_etape_courante=0
518 def del_sdprod(self,sd):
520 Supprime la SD sd de la liste des sd et des dictionnaires de contexte
522 if sd in self.sds : self.sds.remove(sd)
523 if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom]
524 if self.sds_dict.has_key(sd.nom) : del self.sds_dict[sd.nom]
526 def del_param(self,param):
528 Supprime le paramètre param de la liste des paramètres
531 if param in self.params : self.params.remove(param)
532 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
534 def del_fonction(self,fonction):
536 Supprime la fonction fonction de la liste des fonctions
539 if fonction in self.fonctions : self.fonctions.remove(fonction)
540 if self.g_context.has_key(fonction.nom) : del self.g_context[fonction.nom]
542 def append_sdprod(self,sd):
544 Ajoute la SD sd à la liste des sd en vérifiant au préalable qu'une SD de
545 même nom n'existe pas déjà
547 if sd == None or sd.nom == None:return
549 o=self.sds_dict.get(sd.nom,None)
550 if isinstance(o,ASSD):
551 raise AsException("Nom de concept deja defini : %s" % sd.nom)
552 self.sds_dict[sd.nom]=sd
553 self.g_context[sd.nom] = sd
554 if sd not in self.sds : self.sds.append(sd)
556 def append_param(self,param):
558 Ajoute le paramètre param à la liste des params
559 et au contexte global
561 # il faudrait vérifier qu'un paramètre de même nom n'existe pas déjà !!!
562 if param not in self.params : self.params.append(param)
563 self.g_context[param.nom]=param
565 def append_fonction(self,fonction):
567 Ajoute la fonction fonction à la liste des fonctions
568 et au contexte global
570 # il faudrait vérifier qu'une fonction de même nom n'existe pas déjà !!!
571 if fonction not in self.fonctions : self.fonctions.append(fonction)
572 self.g_context[fonction.nom]=fonction
574 def delete_concept_after_etape(self,etape,sd):
576 Met à jour les étapes du JDC qui sont après etape en fonction
577 de la disparition du concept sd
579 index = self.etapes.index(etape)+1
580 if index == len(self.etapes) :
581 return # etape est la dernière étape du jdc ...on ne fait rien !
582 for child in self.etapes[index:]:
583 child.delete_concept(sd)
585 def delete_concept(self,sd):
590 Mettre a jour les etapes du JDC suite à la disparition du
592 Seuls les mots cles simples MCSIMP font un traitement autre
593 que de transmettre aux fils
595 for etape in self.etapes :
596 etape.delete_concept(sd)
598 def replace_concept_after_etape(self,etape,old_sd,sd):
600 Met à jour les étapes du JDC qui sont après etape en fonction
601 du remplacement du concept sd
603 index = self.etapes.index(etape)+1
604 if index == len(self.etapes) :
605 return # etape est la dernière étape du jdc ...on ne fait rien !
606 for child in self.etapes[index:]:
607 child.replace_concept(old_sd,sd)
609 def dump_state(self):
611 print "JDC.state: ",self.state
612 for etape in self.etapes :
613 print etape.nom+".state: ",etape.state
615 #ATTENTION cette methode surcharge la methode du package Validation : a reintegrer
616 def isvalid(self,cr='non'):
618 Méthode booléenne qui retourne 0 si le JDC est invalide, 1 sinon
620 # FR : on prend en compte l'état du JDC ('unchanged','modified','undetermined')
621 # afin d'accélérer le test de validité du JDC
622 if self.state == 'unchanged':
626 texte,test = self.verif_regles()
628 if cr == 'oui': self.cr.fatal(string.strip(texte))
631 for e in self.etapes:
632 if not e.isactif() : continue
636 self.state="unchanged"