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
496 def del_sdprod(self,sd):
498 Supprime la SD sd de la liste des sd et des dictionnaires de contexte
500 #print "del_sdprod",self,sd
501 #print "del_sdprod",self.sds
502 #print "del_sdprod",self.g_context
503 #print "del_sdprod",self.sds_dict
504 if sd in self.sds : self.sds.remove(sd)
505 if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom]
506 if self.sds_dict.has_key(sd.nom) : del self.sds_dict[sd.nom]
508 def del_param(self,param):
510 Supprime le paramètre param de la liste des paramètres
513 if param in self.params : self.params.remove(param)
514 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
516 def del_fonction(self,fonction):
518 Supprime la fonction fonction de la liste des fonctions
521 if fonction in self.fonctions : self.fonctions.remove(fonction)
522 if self.g_context.has_key(fonction.nom) : del self.g_context[fonction.nom]
524 def append_sdprod(self,sd):
526 Ajoute la SD sd à la liste des sd en vérifiant au préalable qu'une SD de
527 même nom n'existe pas déjà
529 if sd == None or sd.nom == None:return
531 o=self.sds_dict.get(sd.nom,None)
532 if isinstance(o,ASSD):
533 raise AsException("Nom de concept deja defini : %s" % sd.nom)
534 self.sds_dict[sd.nom]=sd
535 self.g_context[sd.nom] = sd
536 if sd not in self.sds : self.sds.append(sd)
538 def append_param(self,param):
540 Ajoute le paramètre param à la liste des params
541 et au contexte global
543 # il faudrait vérifier qu'un paramètre de même nom n'existe pas déjà !!!
544 if param not in self.params : self.params.append(param)
545 self.g_context[param.nom]=param
547 def append_fonction(self,fonction):
549 Ajoute la fonction fonction à la liste des fonctions
550 et au contexte global
552 # il faudrait vérifier qu'une fonction de même nom n'existe pas déjà !!!
553 if fonction not in self.fonctions : self.fonctions.append(fonction)
554 self.g_context[fonction.nom]=fonction
556 def delete_concept(self,sd):
561 Mettre a jour les etapes du JDC suite à la disparition du
563 Seuls les mots cles simples MCSIMP font un traitement autre
564 que de transmettre aux fils
566 #print "delete_concept",self,sd
567 for etape in self.etapes :
568 etape.delete_concept(sd)
570 def replace_concept_after_etape(self,etape,old_sd,sd):
572 Met à jour les étapes du JDC qui sont après etape en fonction
573 du remplacement du concept sd
575 index = self.etapes.index(etape)+1
576 if index == len(self.etapes) :
577 return # etape est la dernière étape du jdc ...on ne fait rien !
578 for child in self.etapes[index:]:
579 child.replace_concept(old_sd,sd)
581 def dump_state(self):
583 print "JDC.state: ",self.state
584 for etape in self.etapes :
585 print etape.nom+".state: ",etape.state
587 def change_unit(self,unit,etape,old_unit):
588 #print "change_unit",unit,etape,old_unit
589 #print id(self.recorded_units),self.recorded_units
590 #if self.recorded_units.has_key(old_unit):del self.recorded_units[old_unit]
591 self.record_unit(unit,etape)
593 def record_unit(self,unit,etape):
594 """Enregistre les unites logiques incluses et les infos relatives a l'etape"""
595 #print "record_unit",unit,etape
598 self.recorded_units[None]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
600 self.recorded_units[unit]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
601 #print id(self.recorded_units),self.recorded_units
602 #print self.recorded_units.get(None,(None,"",{}))[2]
603 #print self.recorded_units.get(None,(None,"",{}))[2].get(None,(None,"",{}))
605 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
606 def register(self,etape):
608 Cette méthode ajoute etape dans la liste
609 des etapes self.etapes et retourne l identificateur d'étape
610 fourni par l appel a g_register
612 A quoi sert editmode ?
613 - Si editmode vaut 1, on est en mode edition de JDC. On cherche
614 à enregistrer une étape que l'on a créée avec eficas (en passant
615 par addentite) auquel cas on ne veut récupérer que son numéro
616 d'enregistrement et c'est addentité qui l'enregistre dans
617 self.etapes à la bonne place...
618 - Si editmode vaut 0, on est en mode relecture d'un fichier de
619 commandes et on doit enregistrer l'étape à la fin de self.etapes
620 (dans ce cas l'ordre des étapes est bien l'ordre chronologique
623 if not self.editmode:
624 self.etapes.append(etape)
627 return self.g_register(etape)
629 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
630 def NommerSdprod(self,sd,sdnom,restrict='non'):
632 Nomme la SD apres avoir verifie que le nommage est possible :
634 Si le nom est deja utilise, leve une exception
635 Met le concept créé dans le concept global g_context
637 # XXX En mode editeur dans EFICAS, le nommage doit etre géré différemment
638 # Le dictionnaire g_context ne représente pas le contexte
639 # effectif avant une étape.
640 # Il faut utiliser get_contexte_avant avec indication de l'étape
642 # Cette etape est indiquee par l'attribut _etape_context qui a ete
643 # positionné préalablement par un appel à set_etape_context
645 if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom
647 if self._etape_context:
648 o=self.get_contexte_avant(self._etape_context).get(sdnom,None)
650 o=self.sds_dict.get(sdnom,None)
652 if isinstance(o,ASSD):
653 raise AsException("Nom de concept deja defini : %s" % sdnom)
655 # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
656 # Ajoute a la creation (appel de reg_sd).
657 self.sds_dict[sdnom]=sd
660 # En plus si restrict vaut 'non', on insere le concept dans le contexte du JDC
661 if restrict == 'non':
662 self.g_context[sdnom]=sd
664 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
665 def delete_concept_after_etape(self,etape,sd):
667 Met à jour les étapes du JDC qui sont après etape en fonction
668 de la disparition du concept sd
670 index = self.etapes.index(etape)+1
671 if index == len(self.etapes) :
672 return # etape est la dernière étape du jdc ...on ne fait rien !
673 for child in self.etapes[index:]:
674 child.delete_concept(sd)
676 #ATTENTION SURCHARGE : les methodes ci-dessous surchargent des methodes de Noyau et Validation : a reintegrer