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_LASSD import LASSD
31 from Noyau.N_ETAPE import ETAPE
32 from Noyau.N_Exception import AsException
33 from Extensions import commentaire,parametre,parametre_eval
36 class JDC(I_OBJECT.OBJECT):
41 self.etapes_niveaux=[]
45 self._etape_context=None
46 self.recorded_units={}
47 self.old_recorded_units={}
49 def get_index(self,objet):
51 Retourne la position d'objet dans la liste self
53 return self.etapes.index(objet)
55 def get_sd_avant_du_bon_type(self,etape,types_permis):
57 Retourne la liste des concepts avant etape d'un type acceptable
59 d=self.get_contexte_avant(etape)
62 if type(v) != types.InstanceType : continue
63 # On considère que seul assd indique un type quelconque pas CO
64 elif self.assd in types_permis :
66 elif self.est_permis(v,types_permis):
71 def get_sd_avant_du_bon_type_pour_type_de_base(self,etape,type):
73 Retourne la liste des concepts avant etape d'1 type de base acceptable
74 Attention different de la routine précédente : 1 seul type passé en parametre
75 Teste sur issubclass et par sur le type permis
77 d=self.get_contexte_avant(etape)
80 typeverif=self.cata[0].__dict__[type]
84 if issubclass(v.__class__,typeverif):
89 def cherche_list_avant(self,etape,valeur):
90 d=self.get_contexte_avant(etape)
92 if issubclass(v.__class__,LASSD):
95 # Attention pour enlever les . a la fin des pretendus reels
96 if k == valeur[0:-1] :
100 def est_permis(self,v,types_permis):
101 for type_ok in types_permis:
102 if type_ok in ('R','I','C','TXM') and v in self.params :
104 elif type_ok == 'R' and v.__class__.__name__ == 'reel' :
106 elif type_ok == 'I' and v.__class__.__name__ == 'entier' :
108 elif type_ok == 'C' and v.__class__.__name__ == 'complexe' :
110 elif type_ok == 'TXM' and v.__class__.__name__ == 'chaine' :
112 elif type(type_ok) != types.ClassType :
114 elif v.__class__ == type_ok or issubclass(v.__class__,type_ok):
118 def addentite(self,name,pos):
121 Si name est le nom d une commande ou un commentaire ajoute
123 Sinon remonte une erreur
127 if name == "COMMENTAIRE" :
128 # ajout d'un commentaire
129 self.set_current_step()
131 for child in self.etapes :
132 if isinstance(child,commentaire.COMMENTAIRE):
134 objet = commentaire.COMMENTAIRE('',parent=self)
135 objet.nom = "_comm_"+`ind`
136 if pos == None : pos = 0
137 self.etapes.insert(pos,objet)
140 CONNECTOR.Emit(self,"add",objet)
143 elif name == "PARAMETRE":
144 # ajout d'un parametre
145 self.set_current_step()
146 nom_param = '_param_'+str(len(self.params)+1)
147 objet = parametre.PARAMETRE(nom=nom_param)
148 if pos == None : pos = 0
149 self.etapes.insert(pos,objet)
153 CONNECTOR.Emit(self,"add",objet)
156 elif name == "PARAMETRE_EVAL":
157 # ajout d'un parametre EVAL
158 self.set_current_step()
159 nom_param = '_param_'+str(len(self.params)+1)
160 objet = parametre_eval.PARAMETRE_EVAL(nom=nom_param)
161 if pos == None : pos = 0
162 self.etapes.insert(pos,objet)
166 CONNECTOR.Emit(self,"add",objet)
169 elif type(name)==types.InstanceType:
170 # on est dans le cas où on veut ajouter une commande déjà
171 # existante (par copie donc)
172 # on est donc nécessairement en mode editeur ...
174 # Il ne faut pas oublier de reaffecter le parent d'obj (si copie)
176 self.set_current_step()
177 if isinstance(objet,ETAPE):
178 if objet.nom_niveau_definition == 'JDC':
179 # l'objet dépend directement du JDC
182 # l'étape dépend d'un niveau et non directement du JDC :
183 # il faut l'enregistrer dans le niveau de parent
184 objet.parent.dict_niveaux[objet.nom_niveau_definition].register(objet)
185 objet.niveau = objet.parent.dict_niveaux[objet.nom_niveau_definition]
186 self.etapes.insert(pos,objet)
187 # il faut vérifier que les concepts utilisés par objet existent bien
188 # à ce niveau d'arborescence
189 objet.verif_existence_sd()
193 CONNECTOR.Emit(self,"add",objet)
197 # On veut ajouter une nouvelle commande
199 self.set_current_step()
200 cmd=self.get_cmd(name)
201 # L'appel a make_objet n'a pas pour effet d'enregistrer l'étape
202 # auprès du step courant car editmode vaut 1
203 # Par contre elle a le bon parent grace a set_current_step
205 if pos == None : pos = 0
206 self.etapes.insert(pos,e)
207 self.reset_current_step()
211 CONNECTOR.Emit(self,"add",e)
214 except AsException,e:
215 self.reset_current_step()
217 raise AsException("Impossible d ajouter la commande "+name + '\n' +str(e))
219 traceback.print_exc()
220 self.reset_current_step()
222 raise AsException("Impossible d ajouter la commande "+name)
225 #print "JDC.close",self
226 for etape in self.etapes:
227 if hasattr(etape,"close"):etape.close()
228 CONNECTOR.Emit(self,"close")
230 def set_current_step(self):
231 CONTEXT.unset_current_step()
232 CONTEXT.set_current_step(self)
234 def reset_current_step(self):
235 CONTEXT.unset_current_step()
237 def liste_mc_presents(self):
240 def get_sd_avant_etape(self,nom_sd,etape):
241 return self.get_contexte_avant(etape).get(nom_sd,None)
243 def get_sd_apres_etape_avec_detruire(self,nom_sd,sd,etape,avec='non'):
245 Cette méthode retourne la SD sd de nom nom_sd qui est éventuellement
246 définie apres etape en tenant compte des concepts detruits
247 Si avec vaut 'non' exclut etape de la recherche
249 #print "JDC.get_sd_apres_etape_avec_detruire",nom_sd,sd
250 ietap=self.etapes.index(etape)
251 if avec == 'non':ietap=ietap+1
253 for e in self.etapes[ietap:]:
256 autre_sd=d.get(nom_sd,None)
258 # Le concept a ete detruit. On interrompt la recherche car il n'y a
259 # pas eu de redefinition du concept (il n'y a pas de conflit potentiel).
261 if autre_sd is not sd :
262 # L'etape produit un concept different de meme nom. La situation n'est
263 # pas saine (sauf peut etre si reuse ???)
264 if hasattr(e,'reuse') and e.reuse == autre_sd:
265 # Le concept etant reutilise, on interrompt la recherche.
266 # On considere qu'il n'y a pas de nouveau concept defini
267 # meme si dans les etapes suivantes le concept est detruit
268 # et un concept de meme nom créé.
269 # AVERIFIER : avec reuse le concept devrait etre le meme
270 # le passage par ici est tres improbable
273 # Le concept est produit par l'etape (Il y a conflit potentiel).
274 # Le concept est redefini par une etape posterieure.
276 # Pas de destruction du concept ni de redefinition. On retourne le
280 def get_sd_apres_etape(self,nom_sd,etape,avec='non'):
282 Cette méthode retourne la SD de nom nom_sd qui est éventuellement
284 Si avec vaut 'non' exclut etape de la recherche
286 ietap=self.etapes.index(etape)
287 if avec == 'non':ietap=ietap+1
288 for e in self.etapes[ietap:]:
289 sd=e.get_sdprods(nom_sd)
291 if hasattr(e,'reuse'):
296 def get_sd_autour_etape(self,nom_sd,etape,avec='non'):
298 Fonction: retourne la SD de nom nom_sd qui est éventuellement
299 définie avant ou apres etape
300 Permet de vérifier si un concept de meme nom existe dans le périmètre
302 Si avec vaut 'non' exclut etape de la recherche
304 sd=self.get_sd_avant_etape(nom_sd,etape)
306 return self.get_sd_apres_etape(nom_sd,etape,avec)
308 def get_contexte_apres(self,etape):
310 Retourne le dictionnaire des concepts connus apres etape
311 On tient compte des commandes qui modifient le contexte
312 comme DETRUIRE ou les macros
313 Si etape == None, on retourne le contexte en fin de JDC
315 if not etape: return self.get_contexte_avant(etape)
317 d=self.get_contexte_avant(etape)
318 if etape.isactif():etape.update_context(d)
319 self.index_etape_courante=self.index_etape_courante+1
322 def active_etapes(self):
324 Cette méthode a pour fonction de désactiver les étapes qui doivent
325 l'être cad, dans le cas d'ASTER, les étapes qui ne sont pas
326 comprises entre le premier DEBUT/POURSUITE et le premier FIN
327 et rendre actives les autres
329 if self.definition.code == 'ASTER' :
330 # Seulement pour ASTER :
331 # Avant DEBUT actif vaut 0
332 # Apres DEBUT et avant le 1er FIN actif vaut 1
333 # Apres le 1er FIN actif vaut -1
337 for etape in self.etapes:
338 if actif == 0 and etape.nom in ['DEBUT','POURSUITE']:actif=1
343 if etape.nom == 'FIN':actif=-1
345 def suppentite(self,etape) :
347 Cette methode a pour fonction de supprimer une étape dans
349 Retourne 1 si la suppression a pu être effectuée,
350 Retourne 0 dans le cas contraire
352 #print "suppentite",self
354 #PN correction de bugs
355 if etape not in self.etapes:
357 index_etape=self.etapes.index(etape)
358 self.etapes.remove(etape)
360 if etape.niveau is not self:
361 # Dans ce cas l'étape est enregistrée dans un niveau
362 # Il faut la désenregistrer
363 etape.niveau.unregister(etape)
365 etape.supprime_sdprods()
369 # Apres suppression de l'etape il faut controler que les etapes
370 # suivantes ne produisent pas des concepts DETRUITS dans op_init de etape
372 index_etape=index_etape-1
373 etape=self.etapes[index_etape]
376 self.control_context_apres(etape)
379 CONNECTOR.Emit(self,"supp",etape)
383 def control_context_apres(self,etape):
385 Cette méthode verifie que les etapes apres l'etape etape
386 ont bien des concepts produits acceptables (pas de conflit de
388 Si des concepts produits ne sont pas acceptables ils sont supprimés.
389 Effectue les verifications sur les etapes du jdc mais aussi sur les
390 jdc parents s'ils existent.
392 #print "control_context_apres",self,etape
393 #Regularise les etapes du jdc apres l'etape etape
394 self.control_jdc_context_apres(etape)
396 def control_jdc_context_apres(self,etape):
398 Methode semblable a control_context_apres mais ne travaille
399 que sur les etapes et sous etapes du jdc
401 #print "control_jdc_context_apres",self,etape
403 # on demarre de la premiere etape
406 index_etape=self.etapes.index(etape)+1
409 etape=self.etapes[index_etape]
411 #derniere etape du jdc : rien a faire
414 context=self.get_contexte_avant(etape)
416 for e in self.etapes[index_etape:]:
417 e.control_sdprods(context)
418 e.update_context(context)
422 if not self.cr.estvide():return
426 def register_parametre(self,param):
428 Cette méthode sert à ajouter un paramètre dans la liste des paramètres
430 self.params.append(param)
432 def register_fonction(self,fonction):
434 Cette méthode sert à ajouter une fonction dans la liste des fonctions
436 self.fonctions.append(fonction)
438 def delete_param(self,param):
440 Supprime le paramètre param de la liste des paramètres
443 if param in self.params : self.params.remove(param)
444 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
446 def get_parametres_fonctions_avant_etape(self,etape):
448 Retourne deux éléments :
449 - une liste contenant les noms des paramètres (constantes ou EVAL)
451 - une liste contenant les formules définies avant etape
455 # on récupère le contexte avant etape
456 # on ne peut mettre dans les deux listes que des éléments de ce contexte
457 d=self.get_contexte_avant(etape)
458 # construction de l_constantes
459 for param in self.params:
461 if not nom : continue
462 if d.has_key(nom): l_constantes.append(nom)
463 # construction de l_fonctions
464 for form in self.fonctions:
466 if not nom : continue
467 if d.has_key(nom): l_fonctions.append(form.get_formule())
469 # on ajoute les concepts produits par DEFI_VALEUR
470 # XXX On pourrait peut etre faire plutot le test sur le type
471 # de concept : entier, reel, complexe, etc.
472 for k,v in d.items():
473 if hasattr(v,'etape') and v.etape.nom in ('DEFI_VALEUR',):
474 l_constantes.append(k)
476 # on retourne les deux listes
477 return l_constantes,l_fonctions
479 def get_nb_etapes_avant(self,niveau):
481 Retourne le nombre d etapes avant le debut de niveau
484 for niv in self.etapes_niveaux:
485 if niv == niveau:break
486 nb=nb+len(niv.etapes)
489 def send_message(self,message):
491 self.appli.send_message(message)
493 def init_modif(self):
495 Méthode appelée au moment où une modification va être faite afin de
496 déclencher d'éventuels traitements pré-modification
498 #print "init_modif",self
499 self.state = 'modified'
502 #print "fin_modif",self
503 CONNECTOR.Emit(self,"valid")
507 def deep_update_condition_bloc(self):
508 # pour le moment, on ne fait rien
509 raise "Not implemented"
511 def update_condition_bloc(self):
512 # pour le moment, on ne fait rien
513 raise "Not implemented"
515 def get_liste_mc_inconnus(self):
517 Retourne une liste contenant les mots-clés inconnus à la relecture du JDC
519 # cette liste a le format suivant : [etape,(bloc,mcfact,...),nom_mc,valeur_mc]
521 for etape in self.etapes :
523 if not etape.isvalid() :
524 l = etape.get_liste_mc_inconnus()
525 if l : l_mc.extend(l)
528 def get_genealogie(self):
530 Retourne la liste des noms des ascendants de l'objet self
531 jusqu'à la première ETAPE parent.
535 def get_liste_cmd(self):
537 Retourne la liste des commandes du catalogue
539 return self.niveau.definition.get_liste_cmd()
541 def get_groups(self):
543 Retourne la liste des groupes
545 return self.niveau.definition.liste_groupes,self.niveau.definition.dict_groupes
547 def set_etape_context(self,etape):
549 Positionne l'etape qui sera utilisee dans NommerSdProd pour
550 decider si le concept passé pourra etre nommé
552 self._etape_context=etape
554 def reset_context(self):
556 Cette methode reinitialise le contexte glissant pour pouvoir
557 tenir compte des modifications de l'utilisateur : création
558 de commandes, nommage de concepts, etc.
560 #print "reset_context",self,self.nom
561 self.current_context={}
562 self.index_etape_courante=0
563 # for etape in self.etapes:
564 # etape.reset_context()
566 def del_sdprod(self,sd):
568 Supprime la SD sd de la liste des sd et des dictionnaires de contexte
570 #print "del_sdprod",self,sd
571 #print "del_sdprod",self.sds
572 #print "del_sdprod",self.g_context
573 #print "del_sdprod",self.sds_dict
574 if sd in self.sds : self.sds.remove(sd)
575 if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom]
576 if self.sds_dict.has_key(sd.nom) : del self.sds_dict[sd.nom]
578 def del_param(self,param):
580 Supprime le paramètre param de la liste des paramètres
583 if param in self.params : self.params.remove(param)
584 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
586 def del_fonction(self,fonction):
588 Supprime la fonction fonction de la liste des fonctions
591 if fonction in self.fonctions : self.fonctions.remove(fonction)
592 if self.g_context.has_key(fonction.nom) : del self.g_context[fonction.nom]
594 def append_sdprod(self,sd):
596 Ajoute la SD sd à la liste des sd en vérifiant au préalable qu'une SD de
597 même nom n'existe pas déjà
599 if sd == None or sd.nom == None:return
601 o=self.sds_dict.get(sd.nom,None)
602 if isinstance(o,ASSD):
603 raise AsException("Nom de concept deja defini : %s" % sd.nom)
604 self.sds_dict[sd.nom]=sd
605 self.g_context[sd.nom] = sd
606 if sd not in self.sds : self.sds.append(sd)
608 def append_param(self,param):
610 Ajoute le paramètre param à la liste des params
611 et au contexte global
613 # il faudrait vérifier qu'un paramètre de même nom n'existe pas déjà !!!
614 if param not in self.params : self.params.append(param)
615 self.g_context[param.nom]=param
617 def append_fonction(self,fonction):
619 Ajoute la fonction fonction à la liste des fonctions
620 et au contexte global
622 # il faudrait vérifier qu'une fonction de même nom n'existe pas déjà !!!
623 if fonction not in self.fonctions : self.fonctions.append(fonction)
624 self.g_context[fonction.nom]=fonction
626 def delete_concept(self,sd):
631 Mettre a jour les etapes du JDC suite à la disparition du
633 Seuls les mots cles simples MCSIMP font un traitement autre
634 que de transmettre aux fils
636 #print "delete_concept",self,sd
637 for etape in self.etapes :
638 etape.delete_concept(sd)
640 def replace_concept_after_etape(self,etape,old_sd,sd):
642 Met à jour les étapes du JDC qui sont après etape en fonction
643 du remplacement du concept sd
645 index = self.etapes.index(etape)+1
646 if index == len(self.etapes) :
647 return # etape est la dernière étape du jdc ...on ne fait rien !
648 for child in self.etapes[index:]:
649 child.replace_concept(old_sd,sd)
651 def update_concept_after_etape(self,etape,sd):
653 Met à jour les étapes du JDC qui sont après etape en fonction
654 de la modification (principalement nommage) du concept sd
657 #On traite toutes les etapes
660 index = self.etapes.index(etape)+1
661 if index == len(self.etapes) :
662 return # etape est la dernière étape du jdc ...on ne fait rien !
663 for child in self.etapes[index:]:
664 child.update_concept(sd)
666 def dump_state(self):
667 print "JDC.state: ",self.state
668 for etape in self.etapes :
669 print etape.nom+".state: ",etape.state
671 def change_unit(self,unit,etape,old_unit):
672 #print "change_unit",unit,etape,old_unit
673 #print id(self.recorded_units),self.recorded_units
674 #if self.recorded_units.has_key(old_unit):del self.recorded_units[old_unit]
675 self.record_unit(unit,etape)
677 def record_unit(self,unit,etape):
678 """Enregistre les unites logiques incluses et les infos relatives a l'etape"""
679 #print "record_unit",unit,etape
682 self.recorded_units[None]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
684 self.recorded_units[unit]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
685 #print id(self.recorded_units),self.recorded_units
686 #print self.recorded_units.get(None,(None,"",{}))[2]
687 #print self.recorded_units.get(None,(None,"",{}))[2].get(None,(None,"",{}))
689 def changefichier(self,fichier):
692 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
693 def register(self,etape):
695 Cette méthode ajoute etape dans la liste
696 des etapes self.etapes et retourne l identificateur d'étape
697 fourni par l appel a g_register
699 A quoi sert editmode ?
700 - Si editmode vaut 1, on est en mode edition de JDC. On cherche
701 à enregistrer une étape que l'on a créée avec eficas (en passant
702 par addentite) auquel cas on ne veut récupérer que son numéro
703 d'enregistrement et c'est addentité qui l'enregistre dans
704 self.etapes à la bonne place...
705 - Si editmode vaut 0, on est en mode relecture d'un fichier de
706 commandes et on doit enregistrer l'étape à la fin de self.etapes
707 (dans ce cas l'ordre des étapes est bien l'ordre chronologique
710 if not self.editmode:
711 self.etapes.append(etape)
714 return self.g_register(etape)
716 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
717 def NommerSdprod(self,sd,sdnom,restrict='non'):
719 Nomme la SD apres avoir verifie que le nommage est possible :
721 Si le nom est deja utilise, leve une exception
722 Met le concept créé dans le concept global g_context
724 # XXX En mode editeur dans EFICAS, le nommage doit etre géré différemment
725 # Le dictionnaire g_context ne représente pas le contexte
726 # effectif avant une étape.
727 # Il faut utiliser get_contexte_avant avec indication de l'étape
729 # Cette etape est indiquee par l'attribut _etape_context qui a ete
730 # positionné préalablement par un appel à set_etape_context
732 if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom
734 if self._etape_context:
735 o=self.get_contexte_avant(self._etape_context).get(sdnom,None)
737 o=self.sds_dict.get(sdnom,None)
739 if isinstance(o,ASSD):
740 raise AsException("Nom de concept deja defini : %s" % sdnom)
742 # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
743 # Ajoute a la creation (appel de reg_sd).
744 self.sds_dict[sdnom]=sd
747 # En plus si restrict vaut 'non', on insere le concept dans le contexte du JDC
748 if restrict == 'non':
749 self.g_context[sdnom]=sd
751 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
752 def delete_concept_after_etape(self,etape,sd):
754 Met à jour les étapes du JDC qui sont après etape en fonction
755 de la disparition du concept sd
757 index = self.etapes.index(etape)+1
758 if index == len(self.etapes) :
759 return # etape est la dernière étape du jdc ...on ne fait rien !
760 for child in self.etapes[index:]:
761 child.delete_concept(sd)
763 #ATTENTION SURCHARGE : les methodes ci-dessous surchargent des methodes de Noyau et Validation : a reintegrer
765 def get_file(self,unite=None,fic_origine=''):
767 Retourne le nom du fichier correspondant à un numero d'unité
768 logique (entier) ainsi que le source contenu dans le fichier
771 # Si le JDC est relié à une application maitre, on délègue la recherche
772 file,text= self.appli.get_file(unite,fic_origine)
776 if os.path.exists("fort."+str(unite)):
777 file= "fort."+str(unite)
779 raise AsException("Impossible de trouver le fichier correspondant"
780 " a l unite %s" % unite)
781 if not os.path.exists(file):
782 raise AsException("%s n'est pas un fichier existant" % unite)
786 #if file == None : return None,None
787 text=string.replace(text,'\r\n','\n')
789 linecache.cache[file]=0,0,string.split(text,'\n'),file