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
43 self.recorded_units={}
44 self.old_recorded_units={}
46 def get_cmd(self,nomcmd):
48 Retourne l'objet de type COMMANDE de nom nomcmd
50 for cata in self.cata:
51 if hasattr(cata,nomcmd):
52 return getattr(cata,nomcmd)
54 def get_sd_avant_du_bon_type(self,etape,types_permis):
56 Retourne la liste des concepts avant etape d'un type acceptable
58 d=self.get_contexte_avant(etape)
61 if type(v) != types.InstanceType : continue
62 # On considère que seul assd indique un type quelconque pas CO
63 elif self.assd in types_permis :
65 elif self.est_permis(v,types_permis):
70 def est_permis(self,v,types_permis):
71 for type_ok in types_permis:
72 if type_ok in ('R','I','C','TXM') and v in self.params :
74 elif type_ok == 'R' and v.__class__.__name__ == 'reel' :
76 elif type_ok == 'I' and v.__class__.__name__ == 'entier' :
78 elif type_ok == 'C' and v.__class__.__name__ == 'complexe' :
80 elif type_ok == 'TXM' and v.__class__.__name__ == 'chaine' :
82 elif type(type_ok) != types.ClassType :
84 elif v.__class__ == type_ok or issubclass(v.__class__,type_ok):
88 def addentite(self,name,pos):
91 Si name est le nom d une commande ou un commentaire ajoute
93 Sinon remonte une erreur
97 if name == "COMMENTAIRE" :
98 # ajout d'un commentaire
99 self.set_current_step()
101 for child in self.etapes :
102 if isinstance(child,commentaire.COMMENTAIRE):
104 objet = commentaire.COMMENTAIRE('',parent=self)
105 objet.nom = "_comm_"+`ind`
106 if pos == None : pos = 0
107 self.etapes.insert(pos,objet)
111 elif name == "PARAMETRE":
112 # ajout d'un parametre
113 self.set_current_step()
114 nom_param = '_param_'+str(len(self.params)+1)
115 objet = parametre.PARAMETRE(nom=nom_param)
116 if pos == None : pos = 0
117 self.etapes.insert(pos,objet)
122 elif name == "PARAMETRE_EVAL":
123 # ajout d'un parametre EVAL
124 self.set_current_step()
125 nom_param = '_param_'+str(len(self.params)+1)
126 objet = parametre_eval.PARAMETRE_EVAL(nom=nom_param)
127 if pos == None : pos = 0
128 self.etapes.insert(pos,objet)
133 elif type(name)==types.InstanceType:
134 # on est dans le cas où on veut ajouter une commande déjà
135 # existante (par copie donc)
136 # on est donc nécessairement en mode editeur ...
138 # Il ne faut pas oublier de reaffecter le parent d'obj (si copie)
140 self.set_current_step()
141 if isinstance(objet,ETAPE):
142 if objet.nom_niveau_definition == 'JDC':
143 # l'objet dépend directement du JDC
146 # l'étape dépend d'un niveau et non directement du JDC :
147 # il faut l'enregistrer dans le niveau de parent
148 objet.parent.dict_niveaux[objet.nom_niveau_definition].register(objet)
149 objet.niveau = objet.parent.dict_niveaux[objet.nom_niveau_definition]
150 self.etapes.insert(pos,objet)
151 # il faut vérifier que les concepts utilisés par objet existent bien
152 # à ce niveau d'arborescence
153 objet.verif_existence_sd()
159 # On veut ajouter une nouvelle commande
161 self.set_current_step()
162 cmd=self.get_cmd(name)
163 # L'appel a make_objet n'a pas pour effet d'enregistrer l'étape
164 # auprès du step courant car editmode vaut 1
165 # Par contre elle a le bon parent grace a set_current_step
167 if pos == None : pos = 0
168 self.etapes.insert(pos,e)
169 self.reset_current_step()
175 traceback.print_exc()
176 self.reset_current_step()
178 raise AsException("Impossible d ajouter la commande "+name)
180 def set_current_step(self):
181 CONTEXT.unset_current_step()
182 CONTEXT.set_current_step(self)
184 def reset_current_step(self):
185 CONTEXT.unset_current_step()
187 def liste_mc_presents(self):
190 def get_sd_avant_etape(self,nom_sd,etape):
191 return self.get_contexte_avant(etape).get(nom_sd,None)
193 def get_sd_apres_etape_avec_detruire(self,nom_sd,sd,etape,avec='non'):
195 Cette méthode retourne la SD sd de nom nom_sd qui est éventuellement
196 définie apres etape en tenant compte des concepts detruits
197 Si avec vaut 'non' exclut etape de la recherche
199 ietap=self.etapes.index(etape)
200 if avec == 'non':ietap=ietap+1
202 for e in self.etapes[ietap:]:
205 autre_sd=d.get(nom_sd,None)
207 # Le concept a ete detruit
209 if autre_sd is not sd :
210 # L'etape produit un concept de meme nom
211 if hasattr(e,'reuse') and e.reuse == autre_sd:
212 # Le concept est reutilise, ce n'est pas un produit de l'etape
215 # Le concept est produit par l'etape
217 # On n'a rien trouve. Pas de concept de nom nom_sd
220 def get_sd_apres_etape(self,nom_sd,etape,avec='non'):
222 Cette méthode retourne la SD de nom nom_sd qui est éventuellement
224 Si avec vaut 'non' exclut etape de la recherche
226 ietap=self.etapes.index(etape)
227 if avec == 'non':ietap=ietap+1
228 for e in self.etapes[ietap:]:
229 sd=e.get_sdprods(nom_sd)
231 if hasattr(e,'reuse'):
236 def get_sd_autour_etape(self,nom_sd,etape,avec='non'):
238 Fonction: retourne la SD de nom nom_sd qui est éventuellement
239 définie avant ou apres etape
240 Permet de vérifier si un concept de meme nom existe dans le périmètre
242 Si avec vaut 'non' exclut etape de la recherche
244 sd=self.get_sd_avant_etape(nom_sd,etape)
246 return self.get_sd_apres_etape(nom_sd,etape,avec)
248 def get_contexte_avant(self,etape):
250 Retourne le dictionnaire des concepts connus avant etape
251 On tient compte des commandes qui modifient le contexte
252 comme DETRUIRE ou les macros
253 Si etape == None, on retourne le contexte en fin de JDC
255 # L'étape courante pour laquelle le contexte a été calculé est
256 # mémorisée dans self.index_etape_courante
257 # XXX on pourrait faire mieux dans le cas PAR_LOT="NON" : en
259 # courante pendant le processus de construction des étapes.
260 # Si on insère des commandes (par ex, dans EFICAS), il faut préalablement
261 # remettre ce pointeur à 0
263 index_etape=self.etapes.index(etape)
265 index_etape=len(self.etapes)
266 if index_etape >= self.index_etape_courante:
267 # On calcule le contexte en partant du contexte existant
268 d=self.current_context
269 if self.index_etape_courante==0 and self.context_ini:
270 d.update(self.context_ini)
271 liste_etapes=self.etapes[self.index_etape_courante:index_etape]
273 d=self.current_context={}
274 if self.context_ini:d.update(self.context_ini)
275 liste_etapes=self.etapes
277 for e in liste_etapes:
282 self.index_etape_courante=index_etape
285 def get_contexte_apres(self,etape):
287 Retourne le dictionnaire des concepts connus apres etape
288 On tient compte des commandes qui modifient le contexte
289 comme DETRUIRE ou les macros
290 Si etape == None, on retourne le contexte en fin de JDC
292 if not etape: return self.get_contexte_avant(etape)
294 d=self.get_contexte_avant(etape)
295 if etape.isactif():etape.update_context(d)
296 self.index_etape_courante=self.index_etape_courante+1
299 def active_etapes(self):
301 Cette méthode a pour fonction de désactiver les étapes qui doivent
302 l'être cad, dans le cas d'ASTER, les étapes qui ne sont pas
303 comprises entre le premier DEBUT/POURSUITE et le premier FIN
304 et rendre actives les autres
306 if self.definition.code == 'ASTER' :
307 # Seulement pour ASTER :
308 # Avant DEBUT actif vaut 0
309 # Apres DEBUT et avant le 1er FIN actif vaut 1
310 # Apres le 1er FIN actif vaut -1
314 for etape in self.etapes:
315 if actif == 0 and etape.nom in ['DEBUT','POURSUITE']:actif=1
320 if etape.nom == 'FIN':actif=-1
322 def suppentite(self,etape) :
324 Cette methode a pour fonction de supprimer une étape dans
328 # On memorise le contexte avant l'etape a supprimer
329 d=self.get_contexte_avant(etape)
330 index_etape=self.etapes.index(etape)
332 self.etapes.remove(etape)
333 if etape.niveau is not self:
334 # Dans ce cas l'étape est enregistrée dans un niveau
335 # Il faut la désenregistrer
336 etape.niveau.unregister(etape)
337 etape.supprime_sdprods()
340 # Apres suppression de l'etape il faut controler que les etapes
341 # suivantes ne produisent pas des concepts DETRUITS dans op_init de etape
342 for e in self.etapes[index_etape:]:
350 if not self.cr.estvide():return
354 def register(self,etape):
356 Cette méthode ajoute etape dans la liste
357 des etapes self.etapes et retourne l identificateur d'étape
358 fourni par l appel a g_register
359 A quoi sert editmode ?
360 - Si editmode vaut 1, on est en mode edition de JDC. On cherche
361 à enregistrer une étape que l'on a créée avec eficas (en passant
362 par addentite) auquel cas on ne veut récupérer que son numéro
363 d'enregistrement et c'est addentité qui l'enregistre dans
364 self.etapes à la bonne place...
365 - Si editmode vaut 0, on est en mode relecture d'un fichier de
366 commandes et on doit enregistrer l'étape à la fin de self.etapes
367 (dans ce cas l'ordre des étapes est bien l'ordre chronologique
370 if not self.editmode:
371 self.etapes.append(etape)
374 return self.g_register(etape)
376 def register_parametre(self,param):
378 Cette méthode sert à ajouter un paramètre dans la liste des paramètres
380 self.params.append(param)
382 def register_fonction(self,fonction):
384 Cette méthode sert à ajouter une fonction dans la liste des fonctions
386 self.fonctions.append(fonction)
388 def delete_param(self,param):
390 Supprime le paramètre param de la liste des paramètres
393 if param in self.params : self.params.remove(param)
394 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
396 def get_parametres_fonctions_avant_etape(self,etape):
398 Retourne deux éléments :
399 - une liste contenant les noms des paramètres (constantes ou EVAL)
401 - une liste contenant les formules définies avant etape
405 # on récupère le contexte avant etape
406 # on ne peut mettre dans les deux listes que des éléments de ce contexte
407 d=self.get_contexte_avant(etape)
408 # construction de l_constantes
409 for param in self.params:
411 if not nom : continue
412 if d.has_key(nom): l_constantes.append(nom)
413 # construction de l_fonctions
414 for form in self.fonctions:
416 if not nom : continue
417 if d.has_key(nom): l_fonctions.append(form.get_formule())
419 # on ajoute les concepts produits par DEFI_VALEUR
420 # XXX On pourrait peut etre faire plutot le test sur le type
421 # de concept : entier, reel, complexe, etc.
422 for k,v in d.items():
423 if hasattr(v,'etape') and v.etape.nom in ('DEFI_VALEUR',):
424 l_constantes.append(k)
426 # on retourne les deux listes
427 return l_constantes,l_fonctions
429 def get_nb_etapes_avant(self,niveau):
431 Retourne le nombre d etapes avant le debut de niveau
434 for niv in self.etapes_niveaux:
435 if niv == niveau:break
436 nb=nb+len(niv.etapes)
439 def send_message(self,message):
441 self.appli.send_message(message)
443 def init_modif(self):
445 Méthode appelée au moment où une modification va être faite afin de
446 déclencher d'éventuels traitements pré-modification
448 self.state = 'modified'
454 def get_liste_mc_inconnus(self):
456 Retourne une liste contenant les mots-clés inconnus à la relecture du JDC
458 # cette liste a le format suivant : [etape,(bloc,mcfact,...),nom_mc,valeur_mc]
460 for etape in self.etapes :
462 if not etape.isvalid() :
463 l = etape.get_liste_mc_inconnus()
464 if l : l_mc.extend(l)
467 def get_file(self,unite=None,fic_origine=''):
469 Retourne le nom du fichier correspondant à un numero d'unité
470 logique (entier) ainsi que le source contenu dans le fichier
473 # Si le JDC est relié à une application maitre, on délègue la recherche
474 file,text = self.appli.get_file(unite,fic_origine)
478 if os.path.exists("fort."+str(unite)):
479 file= "fort."+str(unite)
481 raise AsException("Impossible de trouver le fichier correspondant \
482 a l unite %s" % unite)
483 if not os.path.exists(file):
484 raise AsException("%s n'est pas un fichier existant" % unite)
488 if file == None : return None,None
489 text=string.replace(text,'\r\n','\n')
490 linecache.cache[file]=0,0,string.split(text,'\n'),file
494 def get_genealogie(self):
496 Retourne la liste des noms des ascendants de l'objet self
497 jusqu'à la première ETAPE parent.
501 def NommerSdprod(self,sd,sdnom,restrict='non'):
503 Nomme la SD apres avoir verifie que le nommage est possible :
505 Si le nom est deja utilise, leve une exception
506 Met le concept créé dans le concept global g_context
508 # XXX En mode editeur dans EFICAS, le nommage doit etre géré différemment
509 # Le dictionnaire g_context ne représente pas le contexte
510 # effectif avant une étape.
511 # Il faut utiliser get_contexte_avant avec indication de l'étape
513 # Cette etape est indiquee par l'attribut _etape_context qui a ete
514 # positionné préalablement par un appel à set_etape_context
516 if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom
518 if self._etape_context:
519 o=self.get_contexte_avant(self._etape_context).get(sdnom,None)
521 o=self.sds_dict.get(sdnom,None)
523 if isinstance(o,ASSD):
524 raise AsException("Nom de concept deja defini : %s" % sdnom)
526 # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
527 # Ajoute a la creation (appel de reg_sd).
528 self.sds_dict[sdnom]=sd
531 # En plus si restrict vaut 'non', on insere le concept dans le contexte du JDC
532 if restrict == 'non':
533 self.g_context[sdnom]=sd
536 def set_etape_context(self,etape):
538 Positionne l'etape qui sera utilisee dans NommerSdProd pour
539 decider si le concept passé pourra etre nommé
541 self._etape_context=etape
543 def reset_context(self):
545 Cette methode reinitialise le contexte glissant pour pouvoir
546 tenir compte des modifications de l'utilisateur : création
547 de commandes, nommage de concepts, etc.
549 self.current_context={}
550 self.index_etape_courante=0
552 def del_sdprod(self,sd):
554 Supprime la SD sd de la liste des sd et des dictionnaires de contexte
556 if sd in self.sds : self.sds.remove(sd)
557 if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom]
558 if self.sds_dict.has_key(sd.nom) : del self.sds_dict[sd.nom]
560 def del_param(self,param):
562 Supprime le paramètre param de la liste des paramètres
565 if param in self.params : self.params.remove(param)
566 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
568 def del_fonction(self,fonction):
570 Supprime la fonction fonction de la liste des fonctions
573 if fonction in self.fonctions : self.fonctions.remove(fonction)
574 if self.g_context.has_key(fonction.nom) : del self.g_context[fonction.nom]
576 def append_sdprod(self,sd):
578 Ajoute la SD sd à la liste des sd en vérifiant au préalable qu'une SD de
579 même nom n'existe pas déjà
581 if sd == None or sd.nom == None:return
583 o=self.sds_dict.get(sd.nom,None)
584 if isinstance(o,ASSD):
585 raise AsException("Nom de concept deja defini : %s" % sd.nom)
586 self.sds_dict[sd.nom]=sd
587 self.g_context[sd.nom] = sd
588 if sd not in self.sds : self.sds.append(sd)
590 def append_param(self,param):
592 Ajoute le paramètre param à la liste des params
593 et au contexte global
595 # il faudrait vérifier qu'un paramètre de même nom n'existe pas déjà !!!
596 if param not in self.params : self.params.append(param)
597 self.g_context[param.nom]=param
599 def append_fonction(self,fonction):
601 Ajoute la fonction fonction à la liste des fonctions
602 et au contexte global
604 # il faudrait vérifier qu'une fonction de même nom n'existe pas déjà !!!
605 if fonction not in self.fonctions : self.fonctions.append(fonction)
606 self.g_context[fonction.nom]=fonction
608 def delete_concept_after_etape(self,etape,sd):
610 Met à jour les étapes du JDC qui sont après etape en fonction
611 de la disparition du concept sd
613 index = self.etapes.index(etape)+1
614 if index == len(self.etapes) :
615 return # etape est la dernière étape du jdc ...on ne fait rien !
616 for child in self.etapes[index:]:
617 child.delete_concept(sd)
619 def delete_concept(self,sd):
624 Mettre a jour les etapes du JDC suite à la disparition du
626 Seuls les mots cles simples MCSIMP font un traitement autre
627 que de transmettre aux fils
629 for etape in self.etapes :
630 etape.delete_concept(sd)
632 def replace_concept_after_etape(self,etape,old_sd,sd):
634 Met à jour les étapes du JDC qui sont après etape en fonction
635 du remplacement du concept sd
637 index = self.etapes.index(etape)+1
638 if index == len(self.etapes) :
639 return # etape est la dernière étape du jdc ...on ne fait rien !
640 for child in self.etapes[index:]:
641 child.replace_concept(old_sd,sd)
643 def dump_state(self):
645 print "JDC.state: ",self.state
646 for etape in self.etapes :
647 print etape.nom+".state: ",etape.state
649 def change_unit(self,unit,etape,old_unit):
650 if self.recorded_units.has_key(old_unit):del self.recorded_units[old_unit]
651 self.record_unit(unit,etape)
653 def record_unit(self,unit,etape):
654 """Enregistre les unites logiques incluses et les infos relatives a l'etape"""
657 self.recorded_units[None]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
659 self.recorded_units[unit]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
661 #ATTENTION cette methode surcharge la methode du package Validation : a reintegrer
662 def isvalid(self,cr='non'):
664 Méthode booléenne qui retourne 0 si le JDC est invalide, 1 sinon
666 # FR : on prend en compte l'état du JDC ('unchanged','modified','undetermined')
667 # afin d'accélérer le test de validité du JDC
668 if self.state == 'unchanged':
672 texte,test = self.verif_regles()
674 if cr == 'oui': self.cr.fatal(string.strip(texte))
677 for e in self.etapes:
678 if not e.isactif() : continue
682 self.state="unchanged"