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)
145 #if hasattr(objet,'sd'):print "addentite",objet.sd
147 #if hasattr(objet,'sd'):print "addentite",objet.sd
148 self.set_current_step()
149 if isinstance(objet,ETAPE):
150 if objet.nom_niveau_definition == 'JDC':
151 # l'objet dépend directement du JDC
154 # l'étape dépend d'un niveau et non directement du JDC :
155 # il faut l'enregistrer dans le niveau de parent
156 objet.parent.dict_niveaux[objet.nom_niveau_definition].register(objet)
157 objet.niveau = objet.parent.dict_niveaux[objet.nom_niveau_definition]
158 self.etapes.insert(pos,objet)
159 # il faut vérifier que les concepts utilisés par objet existent bien
160 # à ce niveau d'arborescence
161 #if hasattr(objet,'sd'):print "addentite",objet.sd
162 objet.verif_existence_sd()
166 #print "addentite",self.etapes
167 CONNECTOR.Emit(self,"add",objet)
171 # On veut ajouter une nouvelle commande
173 self.set_current_step()
174 cmd=self.get_cmd(name)
175 # L'appel a make_objet n'a pas pour effet d'enregistrer l'étape
176 # auprès du step courant car editmode vaut 1
177 # Par contre elle a le bon parent grace a set_current_step
179 if pos == None : pos = 0
180 self.etapes.insert(pos,e)
181 self.reset_current_step()
185 #print "addentite",self.etapes
186 CONNECTOR.Emit(self,"add",e)
189 except AsException,e:
190 self.reset_current_step()
192 raise AsException("Impossible d ajouter la commande "+name + '\n' +str(e))
194 traceback.print_exc()
195 self.reset_current_step()
197 raise AsException("Impossible d ajouter la commande "+name)
200 #print "JDC.close",self
201 for etape in self.etapes:
202 if hasattr(etape,"close"):etape.close()
203 CONNECTOR.Emit(self,"close")
205 def set_current_step(self):
206 CONTEXT.unset_current_step()
207 CONTEXT.set_current_step(self)
209 def reset_current_step(self):
210 CONTEXT.unset_current_step()
212 def liste_mc_presents(self):
215 def get_sd_avant_etape(self,nom_sd,etape):
216 return self.get_contexte_avant(etape).get(nom_sd,None)
218 def get_sd_apres_etape_avec_detruire(self,nom_sd,sd,etape,avec='non'):
220 Cette méthode retourne la SD sd de nom nom_sd qui est éventuellement
221 définie apres etape en tenant compte des concepts detruits
222 Si avec vaut 'non' exclut etape de la recherche
224 #print "JDC.get_sd_apres_etape_avec_detruire",nom_sd,sd
225 ietap=self.etapes.index(etape)
226 if avec == 'non':ietap=ietap+1
228 for e in self.etapes[ietap:]:
231 autre_sd=d.get(nom_sd,None)
233 # Le concept a ete detruit. On interrompt la recherche car il n'y a
234 # pas eu de redefinition du concept (il n'y a pas de conflit potentiel).
236 if autre_sd is not sd :
237 # L'etape produit un concept different de meme nom. La situation n'est
238 # pas saine (sauf peut etre si reuse ???)
239 if hasattr(e,'reuse') and e.reuse == autre_sd:
240 # Le concept etant reutilise, on interrompt la recherche.
241 # On considere qu'il n'y a pas de nouveau concept defini
242 # meme si dans les etapes suivantes le concept est detruit
243 # et un concept de meme nom créé.
244 # AVERIFIER : avec reuse le concept devrait etre le meme
245 # le passage par ici est tres improbable
248 # Le concept est produit par l'etape (Il y a conflit potentiel).
249 # Le concept est redefini par une etape posterieure.
251 # Pas de destruction du concept ni de redefinition. On retourne le
255 def get_sd_apres_etape(self,nom_sd,etape,avec='non'):
257 Cette méthode retourne la SD de nom nom_sd qui est éventuellement
259 Si avec vaut 'non' exclut etape de la recherche
261 ietap=self.etapes.index(etape)
262 if avec == 'non':ietap=ietap+1
263 for e in self.etapes[ietap:]:
264 sd=e.get_sdprods(nom_sd)
266 if hasattr(e,'reuse'):
271 def get_sd_autour_etape(self,nom_sd,etape,avec='non'):
273 Fonction: retourne la SD de nom nom_sd qui est éventuellement
274 définie avant ou apres etape
275 Permet de vérifier si un concept de meme nom existe dans le périmètre
277 Si avec vaut 'non' exclut etape de la recherche
279 sd=self.get_sd_avant_etape(nom_sd,etape)
281 return self.get_sd_apres_etape(nom_sd,etape,avec)
283 def get_contexte_apres(self,etape):
285 Retourne le dictionnaire des concepts connus apres etape
286 On tient compte des commandes qui modifient le contexte
287 comme DETRUIRE ou les macros
288 Si etape == None, on retourne le contexte en fin de JDC
290 if not etape: return self.get_contexte_avant(etape)
292 d=self.get_contexte_avant(etape)
293 if etape.isactif():etape.update_context(d)
294 self.index_etape_courante=self.index_etape_courante+1
297 def active_etapes(self):
299 Cette méthode a pour fonction de désactiver les étapes qui doivent
300 l'être cad, dans le cas d'ASTER, les étapes qui ne sont pas
301 comprises entre le premier DEBUT/POURSUITE et le premier FIN
302 et rendre actives les autres
304 if self.definition.code == 'ASTER' :
305 # Seulement pour ASTER :
306 # Avant DEBUT actif vaut 0
307 # Apres DEBUT et avant le 1er FIN actif vaut 1
308 # Apres le 1er FIN actif vaut -1
312 for etape in self.etapes:
313 if actif == 0 and etape.nom in ['DEBUT','POURSUITE']:actif=1
318 if etape.nom == 'FIN':actif=-1
320 def suppentite(self,etape) :
322 Cette methode a pour fonction de supprimer une étape dans
324 Retourne 1 si la suppression a pu être effectuée,
325 Retourne 0 dans le cas contraire
327 #print "suppentite",self
329 # On memorise le contexte avant l'etape a supprimer
330 d=self.get_contexte_avant(etape)
331 index_etape=self.etapes.index(etape)
332 #print "suppentite",index_etape,d
334 self.etapes.remove(etape)
335 if etape.niveau is not self:
336 # Dans ce cas l'étape est enregistrée dans un niveau
337 # Il faut la désenregistrer
338 etape.niveau.unregister(etape)
339 etape.supprime_sdprods()
343 # Apres suppression de l'etape il faut controler que les etapes
344 # suivantes ne produisent pas des concepts DETRUITS dans op_init de etape
345 for e in self.etapes[index_etape:]:
349 CONNECTOR.Emit(self,"supp",etape)
355 if not self.cr.estvide():return
359 def register_parametre(self,param):
361 Cette méthode sert à ajouter un paramètre dans la liste des paramètres
363 self.params.append(param)
365 def register_fonction(self,fonction):
367 Cette méthode sert à ajouter une fonction dans la liste des fonctions
369 self.fonctions.append(fonction)
371 def delete_param(self,param):
373 Supprime le paramètre param de la liste des paramètres
376 if param in self.params : self.params.remove(param)
377 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
379 def get_parametres_fonctions_avant_etape(self,etape):
381 Retourne deux éléments :
382 - une liste contenant les noms des paramètres (constantes ou EVAL)
384 - une liste contenant les formules définies avant etape
388 # on récupère le contexte avant etape
389 # on ne peut mettre dans les deux listes que des éléments de ce contexte
390 d=self.get_contexte_avant(etape)
391 # construction de l_constantes
392 for param in self.params:
394 if not nom : continue
395 if d.has_key(nom): l_constantes.append(nom)
396 # construction de l_fonctions
397 for form in self.fonctions:
399 if not nom : continue
400 if d.has_key(nom): l_fonctions.append(form.get_formule())
402 # on ajoute les concepts produits par DEFI_VALEUR
403 # XXX On pourrait peut etre faire plutot le test sur le type
404 # de concept : entier, reel, complexe, etc.
405 for k,v in d.items():
406 if hasattr(v,'etape') and v.etape.nom in ('DEFI_VALEUR',):
407 l_constantes.append(k)
409 # on retourne les deux listes
410 return l_constantes,l_fonctions
412 def get_nb_etapes_avant(self,niveau):
414 Retourne le nombre d etapes avant le debut de niveau
417 for niv in self.etapes_niveaux:
418 if niv == niveau:break
419 nb=nb+len(niv.etapes)
422 def send_message(self,message):
424 self.appli.send_message(message)
426 def init_modif(self):
428 Méthode appelée au moment où une modification va être faite afin de
429 déclencher d'éventuels traitements pré-modification
431 #print "init_modif",self
432 self.state = 'modified'
435 #print "fin_modif",self
436 CONNECTOR.Emit(self,"valid")
440 def deep_update_condition_bloc(self):
441 # pour le moment, on ne fait rien
442 raise "Not implemented"
444 def update_condition_bloc(self):
445 # pour le moment, on ne fait rien
446 raise "Not implemented"
448 def get_liste_mc_inconnus(self):
450 Retourne une liste contenant les mots-clés inconnus à la relecture du JDC
452 # cette liste a le format suivant : [etape,(bloc,mcfact,...),nom_mc,valeur_mc]
454 for etape in self.etapes :
456 if not etape.isvalid() :
457 l = etape.get_liste_mc_inconnus()
458 if l : l_mc.extend(l)
461 def get_genealogie(self):
463 Retourne la liste des noms des ascendants de l'objet self
464 jusqu'à la première ETAPE parent.
468 def get_liste_cmd(self):
470 Retourne la liste des commandes du catalogue
472 return self.niveau.definition.get_liste_cmd()
474 def get_groups(self):
476 Retourne la liste des groupes
478 return self.niveau.definition.liste_groupes,self.niveau.definition.dict_groupes
480 def set_etape_context(self,etape):
482 Positionne l'etape qui sera utilisee dans NommerSdProd pour
483 decider si le concept passé pourra etre nommé
485 self._etape_context=etape
487 def reset_context(self):
489 Cette methode reinitialise le contexte glissant pour pouvoir
490 tenir compte des modifications de l'utilisateur : création
491 de commandes, nommage de concepts, etc.
493 self.current_context={}
494 self.index_etape_courante=0
495 for etape in self.etapes:
496 etape.reset_context()
498 def del_sdprod(self,sd):
500 Supprime la SD sd de la liste des sd et des dictionnaires de contexte
502 #print "del_sdprod",self,sd
503 #print "del_sdprod",self.sds
504 #print "del_sdprod",self.g_context
505 #print "del_sdprod",self.sds_dict
506 if sd in self.sds : self.sds.remove(sd)
507 if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom]
508 if self.sds_dict.has_key(sd.nom) : del self.sds_dict[sd.nom]
510 def del_param(self,param):
512 Supprime le paramètre param de la liste des paramètres
515 if param in self.params : self.params.remove(param)
516 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
518 def del_fonction(self,fonction):
520 Supprime la fonction fonction de la liste des fonctions
523 if fonction in self.fonctions : self.fonctions.remove(fonction)
524 if self.g_context.has_key(fonction.nom) : del self.g_context[fonction.nom]
526 def append_sdprod(self,sd):
528 Ajoute la SD sd à la liste des sd en vérifiant au préalable qu'une SD de
529 même nom n'existe pas déjà
531 if sd == None or sd.nom == None:return
533 o=self.sds_dict.get(sd.nom,None)
534 if isinstance(o,ASSD):
535 raise AsException("Nom de concept deja defini : %s" % sd.nom)
536 self.sds_dict[sd.nom]=sd
537 self.g_context[sd.nom] = sd
538 if sd not in self.sds : self.sds.append(sd)
540 def append_param(self,param):
542 Ajoute le paramètre param à la liste des params
543 et au contexte global
545 # il faudrait vérifier qu'un paramètre de même nom n'existe pas déjà !!!
546 if param not in self.params : self.params.append(param)
547 self.g_context[param.nom]=param
549 def append_fonction(self,fonction):
551 Ajoute la fonction fonction à la liste des fonctions
552 et au contexte global
554 # il faudrait vérifier qu'une fonction de même nom n'existe pas déjà !!!
555 if fonction not in self.fonctions : self.fonctions.append(fonction)
556 self.g_context[fonction.nom]=fonction
558 def delete_concept(self,sd):
563 Mettre a jour les etapes du JDC suite à la disparition du
565 Seuls les mots cles simples MCSIMP font un traitement autre
566 que de transmettre aux fils
568 #print "delete_concept",self,sd
569 for etape in self.etapes :
570 etape.delete_concept(sd)
572 def replace_concept_after_etape(self,etape,old_sd,sd):
574 Met à jour les étapes du JDC qui sont après etape en fonction
575 du remplacement du concept sd
577 index = self.etapes.index(etape)+1
578 if index == len(self.etapes) :
579 return # etape est la dernière étape du jdc ...on ne fait rien !
580 for child in self.etapes[index:]:
581 child.replace_concept(old_sd,sd)
583 def dump_state(self):
585 print "JDC.state: ",self.state
586 for etape in self.etapes :
587 print etape.nom+".state: ",etape.state
589 def change_unit(self,unit,etape,old_unit):
590 #print "change_unit",unit,etape,old_unit
591 #print id(self.recorded_units),self.recorded_units
592 #if self.recorded_units.has_key(old_unit):del self.recorded_units[old_unit]
593 self.record_unit(unit,etape)
595 def record_unit(self,unit,etape):
596 """Enregistre les unites logiques incluses et les infos relatives a l'etape"""
597 #print "record_unit",unit,etape
600 self.recorded_units[None]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
602 self.recorded_units[unit]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
603 #print id(self.recorded_units),self.recorded_units
604 #print self.recorded_units.get(None,(None,"",{}))[2]
605 #print self.recorded_units.get(None,(None,"",{}))[2].get(None,(None,"",{}))
607 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
608 def register(self,etape):
610 Cette méthode ajoute etape dans la liste
611 des etapes self.etapes et retourne l identificateur d'étape
612 fourni par l appel a g_register
614 A quoi sert editmode ?
615 - Si editmode vaut 1, on est en mode edition de JDC. On cherche
616 à enregistrer une étape que l'on a créée avec eficas (en passant
617 par addentite) auquel cas on ne veut récupérer que son numéro
618 d'enregistrement et c'est addentité qui l'enregistre dans
619 self.etapes à la bonne place...
620 - Si editmode vaut 0, on est en mode relecture d'un fichier de
621 commandes et on doit enregistrer l'étape à la fin de self.etapes
622 (dans ce cas l'ordre des étapes est bien l'ordre chronologique
625 if not self.editmode:
626 self.etapes.append(etape)
629 return self.g_register(etape)
631 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
632 def NommerSdprod(self,sd,sdnom,restrict='non'):
634 Nomme la SD apres avoir verifie que le nommage est possible :
636 Si le nom est deja utilise, leve une exception
637 Met le concept créé dans le concept global g_context
639 # XXX En mode editeur dans EFICAS, le nommage doit etre géré différemment
640 # Le dictionnaire g_context ne représente pas le contexte
641 # effectif avant une étape.
642 # Il faut utiliser get_contexte_avant avec indication de l'étape
644 # Cette etape est indiquee par l'attribut _etape_context qui a ete
645 # positionné préalablement par un appel à set_etape_context
647 if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom
649 if self._etape_context:
650 o=self.get_contexte_avant(self._etape_context).get(sdnom,None)
652 o=self.sds_dict.get(sdnom,None)
654 if isinstance(o,ASSD):
655 raise AsException("Nom de concept deja defini : %s" % sdnom)
657 # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
658 # Ajoute a la creation (appel de reg_sd).
659 self.sds_dict[sdnom]=sd
662 # En plus si restrict vaut 'non', on insere le concept dans le contexte du JDC
663 if restrict == 'non':
664 self.g_context[sdnom]=sd
666 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
667 def delete_concept_after_etape(self,etape,sd):
669 Met à jour les étapes du JDC qui sont après etape en fonction
670 de la disparition du concept sd
672 index = self.etapes.index(etape)+1
673 if index == len(self.etapes) :
674 return # etape est la dernière étape du jdc ...on ne fait rien !
675 for child in self.etapes[index:]:
676 child.delete_concept(sd)
678 #ATTENTION SURCHARGE : les methodes ci-dessous surchargent des methodes de Noyau et Validation : a reintegrer