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()
174 except AsException,e:
175 self.reset_current_step()
177 raise AsException("Impossible d ajouter la commande "+name + '\n' +str(e))
179 traceback.print_exc()
180 self.reset_current_step()
182 raise AsException("Impossible d ajouter la commande "+name)
184 def set_current_step(self):
185 CONTEXT.unset_current_step()
186 CONTEXT.set_current_step(self)
188 def reset_current_step(self):
189 CONTEXT.unset_current_step()
191 def liste_mc_presents(self):
194 def get_sd_avant_etape(self,nom_sd,etape):
195 return self.get_contexte_avant(etape).get(nom_sd,None)
197 def get_sd_apres_etape_avec_detruire(self,nom_sd,sd,etape,avec='non'):
199 Cette méthode retourne la SD sd de nom nom_sd qui est éventuellement
200 définie apres etape en tenant compte des concepts detruits
201 Si avec vaut 'non' exclut etape de la recherche
203 ietap=self.etapes.index(etape)
204 if avec == 'non':ietap=ietap+1
206 for e in self.etapes[ietap:]:
209 autre_sd=d.get(nom_sd,None)
211 # Le concept a ete detruit
213 if autre_sd is not sd :
214 # L'etape produit un concept de meme nom
215 if hasattr(e,'reuse') and e.reuse == autre_sd:
216 # Le concept est reutilise, ce n'est pas un produit de l'etape
219 # Le concept est produit par l'etape
221 # On n'a rien trouve. Pas de concept de nom nom_sd
224 def get_sd_apres_etape(self,nom_sd,etape,avec='non'):
226 Cette méthode retourne la SD de nom nom_sd qui est éventuellement
228 Si avec vaut 'non' exclut etape de la recherche
230 ietap=self.etapes.index(etape)
231 if avec == 'non':ietap=ietap+1
232 for e in self.etapes[ietap:]:
233 sd=e.get_sdprods(nom_sd)
235 if hasattr(e,'reuse'):
240 def get_sd_autour_etape(self,nom_sd,etape,avec='non'):
242 Fonction: retourne la SD de nom nom_sd qui est éventuellement
243 définie avant ou apres etape
244 Permet de vérifier si un concept de meme nom existe dans le périmètre
246 Si avec vaut 'non' exclut etape de la recherche
248 sd=self.get_sd_avant_etape(nom_sd,etape)
250 return self.get_sd_apres_etape(nom_sd,etape,avec)
252 def get_contexte_avant(self,etape):
254 Retourne le dictionnaire des concepts connus avant etape
255 On tient compte des commandes qui modifient le contexte
256 comme DETRUIRE ou les macros
257 Si etape == None, on retourne le contexte en fin de JDC
259 # L'étape courante pour laquelle le contexte a été calculé est
260 # mémorisée dans self.index_etape_courante
261 # XXX on pourrait faire mieux dans le cas PAR_LOT="NON" : en
263 # courante pendant le processus de construction des étapes.
264 # Si on insère des commandes (par ex, dans EFICAS), il faut préalablement
265 # remettre ce pointeur à 0
267 index_etape=self.etapes.index(etape)
269 index_etape=len(self.etapes)
270 if index_etape >= self.index_etape_courante:
271 # On calcule le contexte en partant du contexte existant
272 d=self.current_context
273 if self.index_etape_courante==0 and self.context_ini:
274 d.update(self.context_ini)
275 liste_etapes=self.etapes[self.index_etape_courante:index_etape]
277 d=self.current_context={}
278 if self.context_ini:d.update(self.context_ini)
279 liste_etapes=self.etapes
281 for e in liste_etapes:
286 self.index_etape_courante=index_etape
289 def get_contexte_apres(self,etape):
291 Retourne le dictionnaire des concepts connus apres etape
292 On tient compte des commandes qui modifient le contexte
293 comme DETRUIRE ou les macros
294 Si etape == None, on retourne le contexte en fin de JDC
296 if not etape: return self.get_contexte_avant(etape)
298 d=self.get_contexte_avant(etape)
299 if etape.isactif():etape.update_context(d)
300 self.index_etape_courante=self.index_etape_courante+1
303 def active_etapes(self):
305 Cette méthode a pour fonction de désactiver les étapes qui doivent
306 l'être cad, dans le cas d'ASTER, les étapes qui ne sont pas
307 comprises entre le premier DEBUT/POURSUITE et le premier FIN
308 et rendre actives les autres
310 if self.definition.code == 'ASTER' :
311 # Seulement pour ASTER :
312 # Avant DEBUT actif vaut 0
313 # Apres DEBUT et avant le 1er FIN actif vaut 1
314 # Apres le 1er FIN actif vaut -1
318 for etape in self.etapes:
319 if actif == 0 and etape.nom in ['DEBUT','POURSUITE']:actif=1
324 if etape.nom == 'FIN':actif=-1
326 def suppentite(self,etape) :
328 Cette methode a pour fonction de supprimer une étape dans
332 # On memorise le contexte avant l'etape a supprimer
333 d=self.get_contexte_avant(etape)
334 index_etape=self.etapes.index(etape)
336 self.etapes.remove(etape)
337 if etape.niveau is not self:
338 # Dans ce cas l'étape est enregistrée dans un niveau
339 # Il faut la désenregistrer
340 etape.niveau.unregister(etape)
341 etape.supprime_sdprods()
344 # Apres suppression de l'etape il faut controler que les etapes
345 # suivantes ne produisent pas des concepts DETRUITS dans op_init de etape
346 for e in self.etapes[index_etape:]:
354 if not self.cr.estvide():return
358 def register(self,etape):
360 Cette méthode ajoute etape dans la liste
361 des etapes self.etapes et retourne l identificateur d'étape
362 fourni par l appel a g_register
364 A quoi sert editmode ?
365 - Si editmode vaut 1, on est en mode edition de JDC. On cherche
366 à enregistrer une étape que l'on a créée avec eficas (en passant
367 par addentite) auquel cas on ne veut récupérer que son numéro
368 d'enregistrement et c'est addentité qui l'enregistre dans
369 self.etapes à la bonne place...
370 - Si editmode vaut 0, on est en mode relecture d'un fichier de
371 commandes et on doit enregistrer l'étape à la fin de self.etapes
372 (dans ce cas l'ordre des étapes est bien l'ordre chronologique
375 if not self.editmode:
376 self.etapes.append(etape)
379 return self.g_register(etape)
381 def register_parametre(self,param):
383 Cette méthode sert à ajouter un paramètre dans la liste des paramètres
385 self.params.append(param)
387 def register_fonction(self,fonction):
389 Cette méthode sert à ajouter une fonction dans la liste des fonctions
391 self.fonctions.append(fonction)
393 def delete_param(self,param):
395 Supprime le paramètre param de la liste des paramètres
398 if param in self.params : self.params.remove(param)
399 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
401 def get_parametres_fonctions_avant_etape(self,etape):
403 Retourne deux éléments :
404 - une liste contenant les noms des paramètres (constantes ou EVAL)
406 - une liste contenant les formules définies avant etape
410 # on récupère le contexte avant etape
411 # on ne peut mettre dans les deux listes que des éléments de ce contexte
412 d=self.get_contexte_avant(etape)
413 # construction de l_constantes
414 for param in self.params:
416 if not nom : continue
417 if d.has_key(nom): l_constantes.append(nom)
418 # construction de l_fonctions
419 for form in self.fonctions:
421 if not nom : continue
422 if d.has_key(nom): l_fonctions.append(form.get_formule())
424 # on ajoute les concepts produits par DEFI_VALEUR
425 # XXX On pourrait peut etre faire plutot le test sur le type
426 # de concept : entier, reel, complexe, etc.
427 for k,v in d.items():
428 if hasattr(v,'etape') and v.etape.nom in ('DEFI_VALEUR',):
429 l_constantes.append(k)
431 # on retourne les deux listes
432 return l_constantes,l_fonctions
434 def get_nb_etapes_avant(self,niveau):
436 Retourne le nombre d etapes avant le debut de niveau
439 for niv in self.etapes_niveaux:
440 if niv == niveau:break
441 nb=nb+len(niv.etapes)
444 def send_message(self,message):
446 self.appli.send_message(message)
448 def init_modif(self):
450 Méthode appelée au moment où une modification va être faite afin de
451 déclencher d'éventuels traitements pré-modification
453 self.state = 'modified'
459 def get_liste_mc_inconnus(self):
461 Retourne une liste contenant les mots-clés inconnus à la relecture du JDC
463 # cette liste a le format suivant : [etape,(bloc,mcfact,...),nom_mc,valeur_mc]
465 for etape in self.etapes :
467 if not etape.isvalid() :
468 l = etape.get_liste_mc_inconnus()
469 if l : l_mc.extend(l)
472 def get_file(self,unite=None,fic_origine=''):
474 Retourne le nom du fichier correspondant à un numero d'unité
475 logique (entier) ainsi que le source contenu dans le fichier
478 # Si le JDC est relié à une application maitre, on délègue la recherche
479 file,text = self.appli.get_file(unite,fic_origine)
483 if os.path.exists("fort."+str(unite)):
484 file= "fort."+str(unite)
486 raise AsException("Impossible de trouver le fichier correspondant \
487 a l unite %s" % unite)
488 if not os.path.exists(file):
489 raise AsException("%s n'est pas un fichier existant" % unite)
493 if file == None : return None,None
494 text=string.replace(text,'\r\n','\n')
495 linecache.cache[file]=0,0,string.split(text,'\n'),file
499 def get_genealogie(self):
501 Retourne la liste des noms des ascendants de l'objet self
502 jusqu'à la première ETAPE parent.
506 def NommerSdprod(self,sd,sdnom,restrict='non'):
508 Nomme la SD apres avoir verifie que le nommage est possible :
510 Si le nom est deja utilise, leve une exception
511 Met le concept créé dans le concept global g_context
513 # XXX En mode editeur dans EFICAS, le nommage doit etre géré différemment
514 # Le dictionnaire g_context ne représente pas le contexte
515 # effectif avant une étape.
516 # Il faut utiliser get_contexte_avant avec indication de l'étape
518 # Cette etape est indiquee par l'attribut _etape_context qui a ete
519 # positionné préalablement par un appel à set_etape_context
521 if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom
523 if self._etape_context:
524 o=self.get_contexte_avant(self._etape_context).get(sdnom,None)
526 o=self.sds_dict.get(sdnom,None)
528 if isinstance(o,ASSD):
529 raise AsException("Nom de concept deja defini : %s" % sdnom)
531 # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
532 # Ajoute a la creation (appel de reg_sd).
533 self.sds_dict[sdnom]=sd
536 # En plus si restrict vaut 'non', on insere le concept dans le contexte du JDC
537 if restrict == 'non':
538 self.g_context[sdnom]=sd
541 def set_etape_context(self,etape):
543 Positionne l'etape qui sera utilisee dans NommerSdProd pour
544 decider si le concept passé pourra etre nommé
546 self._etape_context=etape
548 def reset_context(self):
550 Cette methode reinitialise le contexte glissant pour pouvoir
551 tenir compte des modifications de l'utilisateur : création
552 de commandes, nommage de concepts, etc.
554 self.current_context={}
555 self.index_etape_courante=0
557 def del_sdprod(self,sd):
559 Supprime la SD sd de la liste des sd et des dictionnaires de contexte
561 if sd in self.sds : self.sds.remove(sd)
562 if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom]
563 if self.sds_dict.has_key(sd.nom) : del self.sds_dict[sd.nom]
565 def del_param(self,param):
567 Supprime le paramètre param de la liste des paramètres
570 if param in self.params : self.params.remove(param)
571 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
573 def del_fonction(self,fonction):
575 Supprime la fonction fonction de la liste des fonctions
578 if fonction in self.fonctions : self.fonctions.remove(fonction)
579 if self.g_context.has_key(fonction.nom) : del self.g_context[fonction.nom]
581 def append_sdprod(self,sd):
583 Ajoute la SD sd à la liste des sd en vérifiant au préalable qu'une SD de
584 même nom n'existe pas déjà
586 if sd == None or sd.nom == None:return
588 o=self.sds_dict.get(sd.nom,None)
589 if isinstance(o,ASSD):
590 raise AsException("Nom de concept deja defini : %s" % sd.nom)
591 self.sds_dict[sd.nom]=sd
592 self.g_context[sd.nom] = sd
593 if sd not in self.sds : self.sds.append(sd)
595 def append_param(self,param):
597 Ajoute le paramètre param à la liste des params
598 et au contexte global
600 # il faudrait vérifier qu'un paramètre de même nom n'existe pas déjà !!!
601 if param not in self.params : self.params.append(param)
602 self.g_context[param.nom]=param
604 def append_fonction(self,fonction):
606 Ajoute la fonction fonction à la liste des fonctions
607 et au contexte global
609 # il faudrait vérifier qu'une fonction de même nom n'existe pas déjà !!!
610 if fonction not in self.fonctions : self.fonctions.append(fonction)
611 self.g_context[fonction.nom]=fonction
613 def delete_concept_after_etape(self,etape,sd):
615 Met à jour les étapes du JDC qui sont après etape en fonction
616 de la disparition du concept sd
618 index = self.etapes.index(etape)+1
619 if index == len(self.etapes) :
620 return # etape est la dernière étape du jdc ...on ne fait rien !
621 for child in self.etapes[index:]:
622 child.delete_concept(sd)
624 def delete_concept(self,sd):
629 Mettre a jour les etapes du JDC suite à la disparition du
631 Seuls les mots cles simples MCSIMP font un traitement autre
632 que de transmettre aux fils
634 for etape in self.etapes :
635 etape.delete_concept(sd)
637 def replace_concept_after_etape(self,etape,old_sd,sd):
639 Met à jour les étapes du JDC qui sont après etape en fonction
640 du remplacement du concept sd
642 index = self.etapes.index(etape)+1
643 if index == len(self.etapes) :
644 return # etape est la dernière étape du jdc ...on ne fait rien !
645 for child in self.etapes[index:]:
646 child.replace_concept(old_sd,sd)
648 def dump_state(self):
650 print "JDC.state: ",self.state
651 for etape in self.etapes :
652 print etape.nom+".state: ",etape.state
654 def change_unit(self,unit,etape,old_unit):
655 if self.recorded_units.has_key(old_unit):del self.recorded_units[old_unit]
656 self.record_unit(unit,etape)
658 def record_unit(self,unit,etape):
659 """Enregistre les unites logiques incluses et les infos relatives a l'etape"""
662 self.recorded_units[None]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
664 self.recorded_units[unit]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
666 #ATTENTION SURCHARGE : cette methode surcharge la methode du package Validation : a reintegrer