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 # ======================================================================
24 import types,traceback
25 import string,linecache
29 from Noyau.N_ASSD import ASSD
30 from Noyau.N_ETAPE import ETAPE
31 from Noyau.N_Exception import AsException
32 from Extensions import commentaire,parametre,parametre_eval
35 class JDC(I_OBJECT.OBJECT):
40 self.etapes_niveaux=[]
44 self._etape_context=None
45 self.recorded_units={}
46 self.old_recorded_units={}
48 def get_index(self,objet):
50 Retourne la position d'objet dans la liste self
52 return self.etapes.index(objet)
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)
110 CONNECTOR.Emit(self,"add",objet)
113 elif name == "PARAMETRE":
114 # ajout d'un parametre
115 self.set_current_step()
116 nom_param = '_param_'+str(len(self.params)+1)
117 objet = parametre.PARAMETRE(nom=nom_param)
118 if pos == None : pos = 0
119 self.etapes.insert(pos,objet)
123 CONNECTOR.Emit(self,"add",objet)
126 elif name == "PARAMETRE_EVAL":
127 # ajout d'un parametre EVAL
128 self.set_current_step()
129 nom_param = '_param_'+str(len(self.params)+1)
130 objet = parametre_eval.PARAMETRE_EVAL(nom=nom_param)
131 if pos == None : pos = 0
132 self.etapes.insert(pos,objet)
136 CONNECTOR.Emit(self,"add",objet)
139 elif type(name)==types.InstanceType:
140 # on est dans le cas où on veut ajouter une commande déjà
141 # existante (par copie donc)
142 # on est donc nécessairement en mode editeur ...
144 # Il ne faut pas oublier de reaffecter le parent d'obj (si copie)
146 self.set_current_step()
147 if isinstance(objet,ETAPE):
148 if objet.nom_niveau_definition == 'JDC':
149 # l'objet dépend directement du JDC
152 # l'étape dépend d'un niveau et non directement du JDC :
153 # il faut l'enregistrer dans le niveau de parent
154 objet.parent.dict_niveaux[objet.nom_niveau_definition].register(objet)
155 objet.niveau = objet.parent.dict_niveaux[objet.nom_niveau_definition]
156 self.etapes.insert(pos,objet)
157 # il faut vérifier que les concepts utilisés par objet existent bien
158 # à ce niveau d'arborescence
159 objet.verif_existence_sd()
163 CONNECTOR.Emit(self,"add",objet)
167 # On veut ajouter une nouvelle commande
169 self.set_current_step()
170 cmd=self.get_cmd(name)
171 # L'appel a make_objet n'a pas pour effet d'enregistrer l'étape
172 # auprès du step courant car editmode vaut 1
173 # Par contre elle a le bon parent grace a set_current_step
175 if pos == None : pos = 0
176 self.etapes.insert(pos,e)
177 self.reset_current_step()
181 CONNECTOR.Emit(self,"add",e)
184 except AsException,e:
185 self.reset_current_step()
187 raise AsException("Impossible d ajouter la commande "+name + '\n' +str(e))
189 traceback.print_exc()
190 self.reset_current_step()
192 raise AsException("Impossible d ajouter la commande "+name)
195 #print "JDC.close",self
196 for etape in self.etapes:
197 if hasattr(etape,"close"):etape.close()
198 CONNECTOR.Emit(self,"close")
200 def set_current_step(self):
201 CONTEXT.unset_current_step()
202 CONTEXT.set_current_step(self)
204 def reset_current_step(self):
205 CONTEXT.unset_current_step()
207 def liste_mc_presents(self):
210 def get_sd_avant_etape(self,nom_sd,etape):
211 return self.get_contexte_avant(etape).get(nom_sd,None)
213 def get_sd_apres_etape_avec_detruire(self,nom_sd,sd,etape,avec='non'):
215 Cette méthode retourne la SD sd de nom nom_sd qui est éventuellement
216 définie apres etape en tenant compte des concepts detruits
217 Si avec vaut 'non' exclut etape de la recherche
219 #print "JDC.get_sd_apres_etape_avec_detruire",nom_sd,sd
220 ietap=self.etapes.index(etape)
221 if avec == 'non':ietap=ietap+1
223 for e in self.etapes[ietap:]:
226 autre_sd=d.get(nom_sd,None)
228 # Le concept a ete detruit. On interrompt la recherche car il n'y a
229 # pas eu de redefinition du concept (il n'y a pas de conflit potentiel).
231 if autre_sd is not sd :
232 # L'etape produit un concept different de meme nom. La situation n'est
233 # pas saine (sauf peut etre si reuse ???)
234 if hasattr(e,'reuse') and e.reuse == autre_sd:
235 # Le concept etant reutilise, on interrompt la recherche.
236 # On considere qu'il n'y a pas de nouveau concept defini
237 # meme si dans les etapes suivantes le concept est detruit
238 # et un concept de meme nom créé.
239 # AVERIFIER : avec reuse le concept devrait etre le meme
240 # le passage par ici est tres improbable
243 # Le concept est produit par l'etape (Il y a conflit potentiel).
244 # Le concept est redefini par une etape posterieure.
246 # Pas de destruction du concept ni de redefinition. On retourne le
250 def get_sd_apres_etape(self,nom_sd,etape,avec='non'):
252 Cette méthode retourne la SD de nom nom_sd qui est éventuellement
254 Si avec vaut 'non' exclut etape de la recherche
256 ietap=self.etapes.index(etape)
257 if avec == 'non':ietap=ietap+1
258 for e in self.etapes[ietap:]:
259 sd=e.get_sdprods(nom_sd)
261 if hasattr(e,'reuse'):
266 def get_sd_autour_etape(self,nom_sd,etape,avec='non'):
268 Fonction: retourne la SD de nom nom_sd qui est éventuellement
269 définie avant ou apres etape
270 Permet de vérifier si un concept de meme nom existe dans le périmètre
272 Si avec vaut 'non' exclut etape de la recherche
274 sd=self.get_sd_avant_etape(nom_sd,etape)
276 return self.get_sd_apres_etape(nom_sd,etape,avec)
278 def get_contexte_apres(self,etape):
280 Retourne le dictionnaire des concepts connus apres etape
281 On tient compte des commandes qui modifient le contexte
282 comme DETRUIRE ou les macros
283 Si etape == None, on retourne le contexte en fin de JDC
285 if not etape: return self.get_contexte_avant(etape)
287 d=self.get_contexte_avant(etape)
288 if etape.isactif():etape.update_context(d)
289 self.index_etape_courante=self.index_etape_courante+1
292 def active_etapes(self):
294 Cette méthode a pour fonction de désactiver les étapes qui doivent
295 l'être cad, dans le cas d'ASTER, les étapes qui ne sont pas
296 comprises entre le premier DEBUT/POURSUITE et le premier FIN
297 et rendre actives les autres
299 if self.definition.code == 'ASTER' :
300 # Seulement pour ASTER :
301 # Avant DEBUT actif vaut 0
302 # Apres DEBUT et avant le 1er FIN actif vaut 1
303 # Apres le 1er FIN actif vaut -1
307 for etape in self.etapes:
308 if actif == 0 and etape.nom in ['DEBUT','POURSUITE']:actif=1
313 if etape.nom == 'FIN':actif=-1
315 def suppentite(self,etape) :
317 Cette methode a pour fonction de supprimer une étape dans
319 Retourne 1 si la suppression a pu être effectuée,
320 Retourne 0 dans le cas contraire
322 #print "suppentite",self
324 #PN correction de bugs
325 if etape not in self.etapes:
327 index_etape=self.etapes.index(etape)
328 self.etapes.remove(etape)
330 if etape.niveau is not self:
331 # Dans ce cas l'étape est enregistrée dans un niveau
332 # Il faut la désenregistrer
333 etape.niveau.unregister(etape)
335 etape.supprime_sdprods()
339 # Apres suppression de l'etape il faut controler que les etapes
340 # suivantes ne produisent pas des concepts DETRUITS dans op_init de etape
342 index_etape=index_etape-1
343 etape=self.etapes[index_etape]
346 self.control_context_apres(etape)
349 CONNECTOR.Emit(self,"supp",etape)
353 def control_context_apres(self,etape):
355 Cette méthode verifie que les etapes apres l'etape etape
356 ont bien des concepts produits acceptables (pas de conflit de
358 Si des concepts produits ne sont pas acceptables ils sont supprimés.
359 Effectue les verifications sur les etapes du jdc mais aussi sur les
360 jdc parents s'ils existent.
362 #print "control_context_apres",self,etape
363 #Regularise les etapes du jdc apres l'etape etape
364 self.control_jdc_context_apres(etape)
366 def control_jdc_context_apres(self,etape):
368 Methode semblable a control_context_apres mais ne travaille
369 que sur les etapes et sous etapes du jdc
371 #print "control_jdc_context_apres",self,etape
373 # on demarre de la premiere etape
376 index_etape=self.etapes.index(etape)+1
379 etape=self.etapes[index_etape]
381 #derniere etape du jdc : rien a faire
384 context=self.get_contexte_avant(etape)
386 for e in self.etapes[index_etape:]:
387 e.control_sdprods(context)
388 e.update_context(context)
392 if not self.cr.estvide():return
396 def register_parametre(self,param):
398 Cette méthode sert à ajouter un paramètre dans la liste des paramètres
400 self.params.append(param)
402 def register_fonction(self,fonction):
404 Cette méthode sert à ajouter une fonction dans la liste des fonctions
406 self.fonctions.append(fonction)
408 def delete_param(self,param):
410 Supprime le paramètre param de la liste des paramètres
413 if param in self.params : self.params.remove(param)
414 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
416 def get_parametres_fonctions_avant_etape(self,etape):
418 Retourne deux éléments :
419 - une liste contenant les noms des paramètres (constantes ou EVAL)
421 - une liste contenant les formules définies avant etape
425 # on récupère le contexte avant etape
426 # on ne peut mettre dans les deux listes que des éléments de ce contexte
427 d=self.get_contexte_avant(etape)
428 # construction de l_constantes
429 for param in self.params:
431 if not nom : continue
432 if d.has_key(nom): l_constantes.append(nom)
433 # construction de l_fonctions
434 for form in self.fonctions:
436 if not nom : continue
437 if d.has_key(nom): l_fonctions.append(form.get_formule())
439 # on ajoute les concepts produits par DEFI_VALEUR
440 # XXX On pourrait peut etre faire plutot le test sur le type
441 # de concept : entier, reel, complexe, etc.
442 for k,v in d.items():
443 if hasattr(v,'etape') and v.etape.nom in ('DEFI_VALEUR',):
444 l_constantes.append(k)
446 # on retourne les deux listes
447 return l_constantes,l_fonctions
449 def get_nb_etapes_avant(self,niveau):
451 Retourne le nombre d etapes avant le debut de niveau
454 for niv in self.etapes_niveaux:
455 if niv == niveau:break
456 nb=nb+len(niv.etapes)
459 def send_message(self,message):
461 self.appli.send_message(message)
463 def init_modif(self):
465 Méthode appelée au moment où une modification va être faite afin de
466 déclencher d'éventuels traitements pré-modification
468 #print "init_modif",self
469 self.state = 'modified'
472 #print "fin_modif",self
473 CONNECTOR.Emit(self,"valid")
477 def deep_update_condition_bloc(self):
478 # pour le moment, on ne fait rien
479 raise "Not implemented"
481 def update_condition_bloc(self):
482 # pour le moment, on ne fait rien
483 raise "Not implemented"
485 def get_liste_mc_inconnus(self):
487 Retourne une liste contenant les mots-clés inconnus à la relecture du JDC
489 # cette liste a le format suivant : [etape,(bloc,mcfact,...),nom_mc,valeur_mc]
491 for etape in self.etapes :
493 if not etape.isvalid() :
494 l = etape.get_liste_mc_inconnus()
495 if l : l_mc.extend(l)
498 def get_genealogie(self):
500 Retourne la liste des noms des ascendants de l'objet self
501 jusqu'à la première ETAPE parent.
505 def get_liste_cmd(self):
507 Retourne la liste des commandes du catalogue
509 return self.niveau.definition.get_liste_cmd()
511 def get_groups(self):
513 Retourne la liste des groupes
515 return self.niveau.definition.liste_groupes,self.niveau.definition.dict_groupes
517 def set_etape_context(self,etape):
519 Positionne l'etape qui sera utilisee dans NommerSdProd pour
520 decider si le concept passé pourra etre nommé
522 self._etape_context=etape
524 def reset_context(self):
526 Cette methode reinitialise le contexte glissant pour pouvoir
527 tenir compte des modifications de l'utilisateur : création
528 de commandes, nommage de concepts, etc.
530 #print "reset_context",self,self.nom
531 self.current_context={}
532 self.index_etape_courante=0
533 # for etape in self.etapes:
534 # etape.reset_context()
536 def del_sdprod(self,sd):
538 Supprime la SD sd de la liste des sd et des dictionnaires de contexte
540 #print "del_sdprod",self,sd
541 #print "del_sdprod",self.sds
542 #print "del_sdprod",self.g_context
543 #print "del_sdprod",self.sds_dict
544 if sd in self.sds : self.sds.remove(sd)
545 if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom]
546 if self.sds_dict.has_key(sd.nom) : del self.sds_dict[sd.nom]
548 def del_param(self,param):
550 Supprime le paramètre param de la liste des paramètres
553 if param in self.params : self.params.remove(param)
554 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
556 def del_fonction(self,fonction):
558 Supprime la fonction fonction de la liste des fonctions
561 if fonction in self.fonctions : self.fonctions.remove(fonction)
562 if self.g_context.has_key(fonction.nom) : del self.g_context[fonction.nom]
564 def append_sdprod(self,sd):
566 Ajoute la SD sd à la liste des sd en vérifiant au préalable qu'une SD de
567 même nom n'existe pas déjà
569 if sd == None or sd.nom == None:return
571 o=self.sds_dict.get(sd.nom,None)
572 if isinstance(o,ASSD):
573 raise AsException("Nom de concept deja defini : %s" % sd.nom)
574 self.sds_dict[sd.nom]=sd
575 self.g_context[sd.nom] = sd
576 if sd not in self.sds : self.sds.append(sd)
578 def append_param(self,param):
580 Ajoute le paramètre param à la liste des params
581 et au contexte global
583 # il faudrait vérifier qu'un paramètre de même nom n'existe pas déjà !!!
584 if param not in self.params : self.params.append(param)
585 self.g_context[param.nom]=param
587 def append_fonction(self,fonction):
589 Ajoute la fonction fonction à la liste des fonctions
590 et au contexte global
592 # il faudrait vérifier qu'une fonction de même nom n'existe pas déjà !!!
593 if fonction not in self.fonctions : self.fonctions.append(fonction)
594 self.g_context[fonction.nom]=fonction
596 def delete_concept(self,sd):
601 Mettre a jour les etapes du JDC suite à la disparition du
603 Seuls les mots cles simples MCSIMP font un traitement autre
604 que de transmettre aux fils
606 #print "delete_concept",self,sd
607 for etape in self.etapes :
608 etape.delete_concept(sd)
610 def replace_concept_after_etape(self,etape,old_sd,sd):
612 Met à jour les étapes du JDC qui sont après etape en fonction
613 du remplacement du concept sd
615 index = self.etapes.index(etape)+1
616 if index == len(self.etapes) :
617 return # etape est la dernière étape du jdc ...on ne fait rien !
618 for child in self.etapes[index:]:
619 child.replace_concept(old_sd,sd)
621 def update_concept_after_etape(self,etape,sd):
623 Met à jour les étapes du JDC qui sont après etape en fonction
624 de la modification (principalement nommage) du concept sd
627 #On traite toutes les etapes
630 index = self.etapes.index(etape)+1
631 if index == len(self.etapes) :
632 return # etape est la dernière étape du jdc ...on ne fait rien !
633 for child in self.etapes[index:]:
634 child.update_concept(sd)
636 def dump_state(self):
637 print "JDC.state: ",self.state
638 for etape in self.etapes :
639 print etape.nom+".state: ",etape.state
641 def change_unit(self,unit,etape,old_unit):
642 #print "change_unit",unit,etape,old_unit
643 #print id(self.recorded_units),self.recorded_units
644 #if self.recorded_units.has_key(old_unit):del self.recorded_units[old_unit]
645 self.record_unit(unit,etape)
647 def record_unit(self,unit,etape):
648 """Enregistre les unites logiques incluses et les infos relatives a l'etape"""
649 #print "record_unit",unit,etape
652 self.recorded_units[None]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
654 self.recorded_units[unit]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
655 #print id(self.recorded_units),self.recorded_units
656 #print self.recorded_units.get(None,(None,"",{}))[2]
657 #print self.recorded_units.get(None,(None,"",{}))[2].get(None,(None,"",{}))
659 def changefichier(self,fichier):
662 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
663 def register(self,etape):
665 Cette méthode ajoute etape dans la liste
666 des etapes self.etapes et retourne l identificateur d'étape
667 fourni par l appel a g_register
669 A quoi sert editmode ?
670 - Si editmode vaut 1, on est en mode edition de JDC. On cherche
671 à enregistrer une étape que l'on a créée avec eficas (en passant
672 par addentite) auquel cas on ne veut récupérer que son numéro
673 d'enregistrement et c'est addentité qui l'enregistre dans
674 self.etapes à la bonne place...
675 - Si editmode vaut 0, on est en mode relecture d'un fichier de
676 commandes et on doit enregistrer l'étape à la fin de self.etapes
677 (dans ce cas l'ordre des étapes est bien l'ordre chronologique
680 if not self.editmode:
681 self.etapes.append(etape)
684 return self.g_register(etape)
686 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
687 def NommerSdprod(self,sd,sdnom,restrict='non'):
689 Nomme la SD apres avoir verifie que le nommage est possible :
691 Si le nom est deja utilise, leve une exception
692 Met le concept créé dans le concept global g_context
694 # XXX En mode editeur dans EFICAS, le nommage doit etre géré différemment
695 # Le dictionnaire g_context ne représente pas le contexte
696 # effectif avant une étape.
697 # Il faut utiliser get_contexte_avant avec indication de l'étape
699 # Cette etape est indiquee par l'attribut _etape_context qui a ete
700 # positionné préalablement par un appel à set_etape_context
702 if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom
704 if self._etape_context:
705 o=self.get_contexte_avant(self._etape_context).get(sdnom,None)
707 o=self.sds_dict.get(sdnom,None)
709 if isinstance(o,ASSD):
710 raise AsException("Nom de concept deja defini : %s" % sdnom)
712 # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
713 # Ajoute a la creation (appel de reg_sd).
714 self.sds_dict[sdnom]=sd
717 # En plus si restrict vaut 'non', on insere le concept dans le contexte du JDC
718 if restrict == 'non':
719 self.g_context[sdnom]=sd
721 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
722 def delete_concept_after_etape(self,etape,sd):
724 Met à jour les étapes du JDC qui sont après etape en fonction
725 de la disparition du concept sd
727 index = self.etapes.index(etape)+1
728 if index == len(self.etapes) :
729 return # etape est la dernière étape du jdc ...on ne fait rien !
730 for child in self.etapes[index:]:
731 child.delete_concept(sd)
733 #ATTENTION SURCHARGE : les methodes ci-dessous surchargent des methodes de Noyau et Validation : a reintegrer
735 def get_file(self,unite=None,fic_origine=''):
737 Retourne le nom du fichier correspondant à un numero d'unité
738 logique (entier) ainsi que le source contenu dans le fichier
741 # Si le JDC est relié à une application maitre, on délègue la recherche
742 file,text= self.appli.get_file(unite,fic_origine)
746 if os.path.exists("fort."+str(unite)):
747 file= "fort."+str(unite)
749 raise AsException("Impossible de trouver le fichier correspondant"
750 " a l unite %s" % unite)
751 if not os.path.exists(file):
752 raise AsException("%s n'est pas un fichier existant" % unite)
756 #if file == None : return None,None
757 text=string.replace(text,'\r\n','\n')
759 linecache.cache[file]=0,0,string.split(text,'\n'),file