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={}
45 def get_cmd(self,nomcmd):
47 Retourne l'objet de type COMMANDE de nom nomcmd
49 for cata in self.cata:
50 if hasattr(cata,nomcmd):
51 return getattr(cata,nomcmd)
53 def get_sd_avant_du_bon_type(self,etape,types_permis):
55 Retourne la liste des concepts avant etape d'un type acceptable
57 d=self.get_contexte_avant(etape)
60 if type(v) != types.InstanceType : continue
61 # On considère que seul assd indique un type quelconque pas CO
62 elif self.assd in types_permis :
64 elif self.est_permis(v,types_permis):
69 def est_permis(self,v,types_permis):
70 for type_ok in types_permis:
71 if type_ok in ('R','I','C','TXM') and v in self.params :
73 elif type_ok == 'R' and v.__class__.__name__ == 'reel' :
75 elif type_ok == 'I' and v.__class__.__name__ == 'entier' :
77 elif type_ok == 'C' and v.__class__.__name__ == 'complexe' :
79 elif type_ok == 'TXM' and v.__class__.__name__ == 'chaine' :
81 elif type(type_ok) != types.ClassType :
83 elif v.__class__ == type_ok or issubclass(v.__class__,type_ok):
87 def addentite(self,name,pos):
90 Si name est le nom d une commande ou un commentaire ajoute
92 Sinon remonte une erreur
96 if name == "COMMENTAIRE" :
97 # ajout d'un commentaire
98 self.set_current_step()
100 for child in self.etapes :
101 if isinstance(child,commentaire.COMMENTAIRE):
103 objet = commentaire.COMMENTAIRE('',parent=self)
104 objet.nom = "_comm_"+`ind`
105 if pos == None : pos = 0
106 self.etapes.insert(pos,objet)
110 elif name == "PARAMETRE":
111 # ajout d'un parametre
112 self.set_current_step()
113 nom_param = '_param_'+str(len(self.params)+1)
114 objet = parametre.PARAMETRE(nom=nom_param)
115 if pos == None : pos = 0
116 self.etapes.insert(pos,objet)
121 elif name == "PARAMETRE_EVAL":
122 # ajout d'un parametre EVAL
123 self.set_current_step()
124 nom_param = '_param_'+str(len(self.params)+1)
125 objet = parametre_eval.PARAMETRE_EVAL(nom=nom_param)
126 if pos == None : pos = 0
127 self.etapes.insert(pos,objet)
132 elif type(name)==types.InstanceType:
133 # on est dans le cas où on veut ajouter une commande déjà
134 # existante (par copie donc)
135 # on est donc nécessairement en mode editeur ...
137 # Il ne faut pas oublier de reaffecter le parent d'obj (si copie)
139 self.set_current_step()
140 if isinstance(objet,ETAPE):
141 if objet.nom_niveau_definition == 'JDC':
142 # l'objet dépend directement du JDC
145 # l'étape dépend d'un niveau et non directement du JDC :
146 # il faut l'enregistrer dans le niveau de parent
147 objet.parent.dict_niveaux[objet.nom_niveau_definition].register(objet)
148 objet.niveau = objet.parent.dict_niveaux[objet.nom_niveau_definition]
149 self.etapes.insert(pos,objet)
150 # il faut vérifier que les concepts utilisés par objet existent bien
151 # à ce niveau d'arborescence
152 objet.verif_existence_sd()
158 # On veut ajouter une nouvelle commande
160 self.set_current_step()
161 cmd=self.get_cmd(name)
162 # L'appel a make_objet n'a pas pour effet d'enregistrer l'étape
163 # auprès du step courant car editmode vaut 1
164 # Par contre elle a le bon parent grace a set_current_step
166 if pos == None : pos = 0
167 self.etapes.insert(pos,e)
168 self.reset_current_step()
174 traceback.print_exc()
175 self.reset_current_step()
177 raise AsException("Impossible d ajouter la commande "+name)
179 def set_current_step(self):
180 CONTEXT.unset_current_step()
181 CONTEXT.set_current_step(self)
183 def reset_current_step(self):
184 CONTEXT.unset_current_step()
186 def liste_mc_presents(self):
189 def get_sd_avant_etape(self,nom_sd,etape):
190 return self.get_contexte_avant(etape).get(nom_sd,None)
192 def get_sd_apres_etape(self,nom_sd,etape,avec='non'):
194 Cette méthode retourne la SD de nom nom_sd qui est éventuellement
196 Si avec vaut 'non' exclut etape de la recherche
198 ietap=self.etapes.index(etape)
199 if avec == 'non':ietap=ietap+1
200 for e in self.etapes[ietap:]:
201 sd=e.get_sdprods(nom_sd)
203 if hasattr(e,'reuse'):
208 def get_sd_autour_etape(self,nom_sd,etape,avec='non'):
210 Fonction: retourne la SD de nom nom_sd qui est éventuellement
211 définie avant ou apres etape
212 Permet de vérifier si un concept de meme nom existe dans le périmètre
214 Si avec vaut 'non' exclut etape de la recherche
216 sd=self.get_sd_avant_etape(nom_sd,etape)
218 return self.get_sd_apres_etape(nom_sd,etape,avec)
220 def get_contexte_avant(self,etape):
222 Retourne le dictionnaire des concepts connus avant etape
223 On tient compte des commandes qui modifient le contexte
224 comme DETRUIRE ou les macros
225 Si etape == None, on retourne le contexte en fin de JDC
227 # L'étape courante pour laquelle le contexte a été calculé est
228 # mémorisée dans self.index_etape_courante
229 # XXX on pourrait faire mieux dans le cas PAR_LOT="NON" : en
231 # courante pendant le processus de construction des étapes.
232 # Si on insère des commandes (par ex, dans EFICAS), il faut préalablement
233 # remettre ce pointeur à 0
235 index_etape=self.etapes.index(etape)
237 index_etape=len(self.etapes)
238 if index_etape >= self.index_etape_courante:
239 # On calcule le contexte en partant du contexte existant
240 d=self.current_context
241 if self.index_etape_courante==0 and self.context_ini:
242 d.update(self.context_ini)
243 liste_etapes=self.etapes[self.index_etape_courante:index_etape]
245 d=self.current_context={}
246 if self.context_ini:d.update(self.context_ini)
247 liste_etapes=self.etapes
249 for e in liste_etapes:
254 self.index_etape_courante=index_etape
257 def get_contexte_apres(self,etape):
259 Retourne le dictionnaire des concepts connus apres etape
260 On tient compte des commandes qui modifient le contexte
261 comme DETRUIRE ou les macros
262 Si etape == None, on retourne le contexte en fin de JDC
264 if not etape: return self.get_contexte_avant(etape)
266 d=self.get_contexte_avant(etape)
267 if etape.isactif():etape.update_context(d)
268 self.index_etape_courante=self.index_etape_courante+1
271 def active_etapes(self):
273 Cette méthode a pour fonction de désactiver les étapes qui doivent
274 l'être cad, dans le cas d'ASTER, les étapes qui ne sont pas
275 comprises entre le premier DEBUT/POURSUITE et le premier FIN
276 et rendre actives les autres
278 if self.definition.code == 'ASTER' :
279 # Seulement pour ASTER :
280 # Avant DEBUT actif vaut 0
281 # Apres DEBUT et avant le 1er FIN actif vaut 1
282 # Apres le 1er FIN actif vaut -1
286 for etape in self.etapes:
287 if actif == 0 and etape.nom in ['DEBUT','POURSUITE']:actif=1
292 if etape.nom == 'FIN':actif=-1
294 def suppentite(self,etape) :
296 Cette methode a pour fonction de supprimer une étape dans
300 # On memorise le contexte avant l'etape a supprimer
301 d=self.get_contexte_avant(etape)
302 index_etape=self.etapes.index(etape)
304 self.etapes.remove(etape)
305 if etape.niveau is not self:
306 # Dans ce cas l'étape est enregistrée dans un niveau
307 # Il faut la désenregistrer
308 etape.niveau.unregister(etape)
309 etape.supprime_sdprods()
312 # Apres suppression de l'etape il faut controler que les etapes
313 # suivantes ne produisent pas des concepts DETRUITS dans op_init de etape
314 for e in self.etapes[index_etape:]:
322 if not self.cr.estvide():return
326 def register(self,etape):
328 Cette méthode ajoute etape dans la liste
329 des etapes self.etapes et retourne l identificateur d'étape
330 fourni par l appel a g_register
331 A quoi sert editmode ?
332 - Si editmode vaut 1, on est en mode edition de JDC. On cherche
333 à enregistrer une étape que l'on a créée avec eficas (en passant
334 par addentite) auquel cas on ne veut récupérer que son numéro
335 d'enregistrement et c'est addentité qui l'enregistre dans
336 self.etapes à la bonne place...
337 - Si editmode vaut 0, on est en mode relecture d'un fichier de
338 commandes et on doit enregistrer l'étape à la fin de self.etapes
339 (dans ce cas l'ordre des étapes est bien l'ordre chronologique
342 if not self.editmode:
343 self.etapes.append(etape)
346 return self.g_register(etape)
348 def register_parametre(self,param):
350 Cette méthode sert à ajouter un paramètre dans la liste des paramètres
352 self.params.append(param)
354 def register_fonction(self,fonction):
356 Cette méthode sert à ajouter une fonction dans la liste des fonctions
358 self.fonctions.append(fonction)
360 def delete_param(self,param):
362 Supprime le paramètre param de la liste des paramètres
365 if param in self.params : self.params.remove(param)
366 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
368 def get_parametres_fonctions_avant_etape(self,etape):
370 Retourne deux éléments :
371 - une liste contenant les noms des paramètres (constantes ou EVAL)
373 - une liste contenant les formules définies avant etape
377 # on récupère le contexte avant etape
378 # on ne peut mettre dans les deux listes que des éléments de ce contexte
379 d=self.get_contexte_avant(etape)
380 # construction de l_constantes
381 for param in self.params:
383 if not nom : continue
384 if d.has_key(nom): l_constantes.append(nom)
385 # construction de l_fonctions
386 for form in self.fonctions:
388 if not nom : continue
389 if d.has_key(nom): l_fonctions.append(form.get_formule())
391 # on ajoute les concepts produits par DEFI_VALEUR
392 # XXX On pourrait peut etre faire plutot le test sur le type
393 # de concept : entier, reel, complexe, etc.
394 for k,v in d.items():
395 if hasattr(v,'etape') and v.etape.nom in ('DEFI_VALEUR',):
396 l_constantes.append(k)
398 # on retourne les deux listes
399 return l_constantes,l_fonctions
401 def get_nb_etapes_avant(self,niveau):
403 Retourne le nombre d etapes avant le debut de niveau
406 for niv in self.etapes_niveaux:
407 if niv == niveau:break
408 nb=nb+len(niv.etapes)
411 def send_message(self,message):
413 self.appli.send_message(message)
415 def init_modif(self):
417 Méthode appelée au moment où une modification va être faite afin de
418 déclencher d'éventuels traitements pré-modification
420 self.state = 'modified'
426 def get_liste_mc_inconnus(self):
428 Retourne une liste contenant les mots-clés inconnus à la relecture du JDC
430 # cette liste a le format suivant : [etape,(bloc,mcfact,...),nom_mc,valeur_mc]
432 for etape in self.etapes :
434 if not etape.isvalid() :
435 l = etape.get_liste_mc_inconnus()
436 if l : l_mc.extend(l)
439 def get_file(self,unite=None,fic_origine=''):
441 Retourne le nom du fichier correspondant à un numero d'unité
442 logique (entier) ainsi que le source contenu dans le fichier
444 if self.recorded_units.has_key(unite):
445 return self.recorded_units[unite]
447 # Si le JDC est relié à une application maitre, on délègue la recherche
448 file,text = self.appli.get_file(unite,fic_origine)
452 if os.path.exists("fort."+str(unite)):
453 file= "fort."+str(unite)
455 raise AsException("Impossible de trouver le fichier correspondant \
456 a l unite %s" % unite)
457 if not os.path.exists(file):
458 raise AsException("%s n'est pas un fichier existant" % unite)
462 if file == None : return None,None
463 text=string.replace(text,'\r\n','\n')
464 linecache.cache[file]=0,0,string.split(text,'\n'),file
468 def get_genealogie(self):
470 Retourne la liste des noms des ascendants de l'objet self
471 jusqu'à la première ETAPE parent.
475 def NommerSdprod(self,sd,sdnom,restrict='non'):
477 Nomme la SD apres avoir verifie que le nommage est possible :
479 Si le nom est deja utilise, leve une exception
480 Met le concept créé dans le concept global g_context
482 # XXX En mode editeur dans EFICAS, le nommage doit etre géré différemment
483 # Le dictionnaire g_context ne représente pas le contexte
484 # effectif avant une étape.
485 # Il faut utiliser get_contexte_avant avec indication de l'étape
487 # Cette etape est indiquee par l'attribut _etape_context qui a ete
488 # positionné préalablement par un appel à set_etape_context
490 if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom
492 if self._etape_context:
493 o=self.get_contexte_avant(self._etape_context).get(sdnom,None)
495 o=self.sds_dict.get(sdnom,None)
497 if isinstance(o,ASSD):
498 raise AsException("Nom de concept deja defini : %s" % sdnom)
500 # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
501 # Ajoute a la creation (appel de reg_sd).
502 self.sds_dict[sdnom]=sd
505 def set_etape_context(self,etape):
507 Positionne l'etape qui sera utilisee dans NommerSdProd pour
508 decider si le concept passé pourra etre nommé
510 self._etape_context=etape
512 def reset_context(self):
514 Cette methode reinitialise le contexte glissant pour pouvoir
515 tenir compte des modifications de l'utilisateur : création
516 de commandes, nommage de concepts, etc.
518 self.current_context={}
519 self.index_etape_courante=0
521 def del_sdprod(self,sd):
523 Supprime la SD sd de la liste des sd et des dictionnaires de contexte
525 if sd in self.sds : self.sds.remove(sd)
526 if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom]
527 if self.sds_dict.has_key(sd.nom) : del self.sds_dict[sd.nom]
529 def del_param(self,param):
531 Supprime le paramètre param de la liste des paramètres
534 if param in self.params : self.params.remove(param)
535 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
537 def del_fonction(self,fonction):
539 Supprime la fonction fonction de la liste des fonctions
542 if fonction in self.fonctions : self.fonctions.remove(fonction)
543 if self.g_context.has_key(fonction.nom) : del self.g_context[fonction.nom]
545 def append_sdprod(self,sd):
547 Ajoute la SD sd à la liste des sd en vérifiant au préalable qu'une SD de
548 même nom n'existe pas déjà
550 if sd == None or sd.nom == None:return
552 o=self.sds_dict.get(sd.nom,None)
553 if isinstance(o,ASSD):
554 raise AsException("Nom de concept deja defini : %s" % sd.nom)
555 self.sds_dict[sd.nom]=sd
556 self.g_context[sd.nom] = sd
557 if sd not in self.sds : self.sds.append(sd)
559 def append_param(self,param):
561 Ajoute le paramètre param à la liste des params
562 et au contexte global
564 # il faudrait vérifier qu'un paramètre de même nom n'existe pas déjà !!!
565 if param not in self.params : self.params.append(param)
566 self.g_context[param.nom]=param
568 def append_fonction(self,fonction):
570 Ajoute la fonction fonction à la liste des fonctions
571 et au contexte global
573 # il faudrait vérifier qu'une fonction de même nom n'existe pas déjà !!!
574 if fonction not in self.fonctions : self.fonctions.append(fonction)
575 self.g_context[fonction.nom]=fonction
577 def delete_concept_after_etape(self,etape,sd):
579 Met à jour les étapes du JDC qui sont après etape en fonction
580 de la disparition du concept sd
582 index = self.etapes.index(etape)+1
583 if index == len(self.etapes) :
584 return # etape est la dernière étape du jdc ...on ne fait rien !
585 for child in self.etapes[index:]:
586 child.delete_concept(sd)
588 def delete_concept(self,sd):
593 Mettre a jour les etapes du JDC suite à la disparition du
595 Seuls les mots cles simples MCSIMP font un traitement autre
596 que de transmettre aux fils
598 for etape in self.etapes :
599 etape.delete_concept(sd)
601 def replace_concept_after_etape(self,etape,old_sd,sd):
603 Met à jour les étapes du JDC qui sont après etape en fonction
604 du remplacement du concept sd
606 index = self.etapes.index(etape)+1
607 if index == len(self.etapes) :
608 return # etape est la dernière étape du jdc ...on ne fait rien !
609 for child in self.etapes[index:]:
610 child.replace_concept(old_sd,sd)
612 def dump_state(self):
614 print "JDC.state: ",self.state
615 for etape in self.etapes :
616 print etape.nom+".state: ",etape.state
618 def record_unit(self,unit,etape):
619 """Enregistre les unites logiques incluses et les infos relatives a l'etape"""
622 self.recorded_units[None]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
624 self.recorded_units[unit]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
626 #ATTENTION cette methode surcharge la methode du package Validation : a reintegrer
627 def isvalid(self,cr='non'):
629 Méthode booléenne qui retourne 0 si le JDC est invalide, 1 sinon
631 # FR : on prend en compte l'état du JDC ('unchanged','modified','undetermined')
632 # afin d'accélérer le test de validité du JDC
633 if self.state == 'unchanged':
637 texte,test = self.verif_regles()
639 if cr == 'oui': self.cr.fatal(string.strip(texte))
642 for e in self.etapes:
643 if not e.isactif() : continue
647 self.state="unchanged"