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
34 class JDC(I_OBJECT.OBJECT):
39 self.etapes_niveaux=[]
43 self._etape_context=None
44 self.recorded_units={}
45 self.old_recorded_units={}
47 def get_sd_avant_du_bon_type(self,etape,types_permis):
49 Retourne la liste des concepts avant etape d'un type acceptable
51 d=self.get_contexte_avant(etape)
54 if type(v) != types.InstanceType : continue
55 # On considère que seul assd indique un type quelconque pas CO
56 elif self.assd in types_permis :
58 elif self.est_permis(v,types_permis):
63 def est_permis(self,v,types_permis):
64 for type_ok in types_permis:
65 if type_ok in ('R','I','C','TXM') and v in self.params :
67 elif type_ok == 'R' and v.__class__.__name__ == 'reel' :
69 elif type_ok == 'I' and v.__class__.__name__ == 'entier' :
71 elif type_ok == 'C' and v.__class__.__name__ == 'complexe' :
73 elif type_ok == 'TXM' and v.__class__.__name__ == 'chaine' :
75 elif type(type_ok) != types.ClassType :
77 elif v.__class__ == type_ok or issubclass(v.__class__,type_ok):
81 def addentite(self,name,pos):
84 Si name est le nom d une commande ou un commentaire ajoute
86 Sinon remonte une erreur
90 if name == "COMMENTAIRE" :
91 # ajout d'un commentaire
92 self.set_current_step()
94 for child in self.etapes :
95 if isinstance(child,commentaire.COMMENTAIRE):
97 objet = commentaire.COMMENTAIRE('',parent=self)
98 objet.nom = "_comm_"+`ind`
99 if pos == None : pos = 0
100 self.etapes.insert(pos,objet)
104 elif name == "PARAMETRE":
105 # ajout d'un parametre
106 self.set_current_step()
107 nom_param = '_param_'+str(len(self.params)+1)
108 objet = parametre.PARAMETRE(nom=nom_param)
109 if pos == None : pos = 0
110 self.etapes.insert(pos,objet)
115 elif name == "PARAMETRE_EVAL":
116 # ajout d'un parametre EVAL
117 self.set_current_step()
118 nom_param = '_param_'+str(len(self.params)+1)
119 objet = parametre_eval.PARAMETRE_EVAL(nom=nom_param)
120 if pos == None : pos = 0
121 self.etapes.insert(pos,objet)
126 elif type(name)==types.InstanceType:
127 # on est dans le cas où on veut ajouter une commande déjà
128 # existante (par copie donc)
129 # on est donc nécessairement en mode editeur ...
131 # Il ne faut pas oublier de reaffecter le parent d'obj (si copie)
133 self.set_current_step()
134 if isinstance(objet,ETAPE):
135 if objet.nom_niveau_definition == 'JDC':
136 # l'objet dépend directement du JDC
139 # l'étape dépend d'un niveau et non directement du JDC :
140 # il faut l'enregistrer dans le niveau de parent
141 objet.parent.dict_niveaux[objet.nom_niveau_definition].register(objet)
142 objet.niveau = objet.parent.dict_niveaux[objet.nom_niveau_definition]
143 self.etapes.insert(pos,objet)
144 # il faut vérifier que les concepts utilisés par objet existent bien
145 # à ce niveau d'arborescence
146 objet.verif_existence_sd()
152 # On veut ajouter une nouvelle commande
154 self.set_current_step()
155 cmd=self.get_cmd(name)
156 # L'appel a make_objet n'a pas pour effet d'enregistrer l'étape
157 # auprès du step courant car editmode vaut 1
158 # Par contre elle a le bon parent grace a set_current_step
160 if pos == None : pos = 0
161 self.etapes.insert(pos,e)
162 self.reset_current_step()
167 except AsException,e:
168 self.reset_current_step()
170 raise AsException("Impossible d ajouter la commande "+name + '\n' +str(e))
172 traceback.print_exc()
173 self.reset_current_step()
175 raise AsException("Impossible d ajouter la commande "+name)
177 def set_current_step(self):
178 CONTEXT.unset_current_step()
179 CONTEXT.set_current_step(self)
181 def reset_current_step(self):
182 CONTEXT.unset_current_step()
184 def liste_mc_presents(self):
187 def get_sd_avant_etape(self,nom_sd,etape):
188 return self.get_contexte_avant(etape).get(nom_sd,None)
190 def get_sd_apres_etape_avec_detruire(self,nom_sd,sd,etape,avec='non'):
192 Cette méthode retourne la SD sd de nom nom_sd qui est éventuellement
193 définie apres etape en tenant compte des concepts detruits
194 Si avec vaut 'non' exclut etape de la recherche
196 ietap=self.etapes.index(etape)
197 if avec == 'non':ietap=ietap+1
199 for e in self.etapes[ietap:]:
202 autre_sd=d.get(nom_sd,None)
204 # Le concept a ete detruit
206 if autre_sd is not sd :
207 # L'etape produit un concept de meme nom
208 if hasattr(e,'reuse') and e.reuse == autre_sd:
209 # Le concept est reutilise, ce n'est pas un produit de l'etape
212 # Le concept est produit par l'etape
214 # On n'a rien trouve. Pas de concept de nom nom_sd
217 def get_sd_apres_etape(self,nom_sd,etape,avec='non'):
219 Cette méthode retourne la SD de nom nom_sd qui est éventuellement
221 Si avec vaut 'non' exclut etape de la recherche
223 ietap=self.etapes.index(etape)
224 if avec == 'non':ietap=ietap+1
225 for e in self.etapes[ietap:]:
226 sd=e.get_sdprods(nom_sd)
228 if hasattr(e,'reuse'):
233 def get_sd_autour_etape(self,nom_sd,etape,avec='non'):
235 Fonction: retourne la SD de nom nom_sd qui est éventuellement
236 définie avant ou apres etape
237 Permet de vérifier si un concept de meme nom existe dans le périmètre
239 Si avec vaut 'non' exclut etape de la recherche
241 sd=self.get_sd_avant_etape(nom_sd,etape)
243 return self.get_sd_apres_etape(nom_sd,etape,avec)
245 def get_contexte_apres(self,etape):
247 Retourne le dictionnaire des concepts connus apres etape
248 On tient compte des commandes qui modifient le contexte
249 comme DETRUIRE ou les macros
250 Si etape == None, on retourne le contexte en fin de JDC
252 if not etape: return self.get_contexte_avant(etape)
254 d=self.get_contexte_avant(etape)
255 if etape.isactif():etape.update_context(d)
256 self.index_etape_courante=self.index_etape_courante+1
259 def active_etapes(self):
261 Cette méthode a pour fonction de désactiver les étapes qui doivent
262 l'être cad, dans le cas d'ASTER, les étapes qui ne sont pas
263 comprises entre le premier DEBUT/POURSUITE et le premier FIN
264 et rendre actives les autres
266 if self.definition.code == 'ASTER' :
267 # Seulement pour ASTER :
268 # Avant DEBUT actif vaut 0
269 # Apres DEBUT et avant le 1er FIN actif vaut 1
270 # Apres le 1er FIN actif vaut -1
274 for etape in self.etapes:
275 if actif == 0 and etape.nom in ['DEBUT','POURSUITE']:actif=1
280 if etape.nom == 'FIN':actif=-1
282 def suppentite(self,etape) :
284 Cette methode a pour fonction de supprimer une étape dans
288 # On memorise le contexte avant l'etape a supprimer
289 d=self.get_contexte_avant(etape)
290 index_etape=self.etapes.index(etape)
292 self.etapes.remove(etape)
293 if etape.niveau is not self:
294 # Dans ce cas l'étape est enregistrée dans un niveau
295 # Il faut la désenregistrer
296 etape.niveau.unregister(etape)
297 etape.supprime_sdprods()
300 # Apres suppression de l'etape il faut controler que les etapes
301 # suivantes ne produisent pas des concepts DETRUITS dans op_init de etape
302 for e in self.etapes[index_etape:]:
310 if not self.cr.estvide():return
314 def register_parametre(self,param):
316 Cette méthode sert à ajouter un paramètre dans la liste des paramètres
318 self.params.append(param)
320 def register_fonction(self,fonction):
322 Cette méthode sert à ajouter une fonction dans la liste des fonctions
324 self.fonctions.append(fonction)
326 def delete_param(self,param):
328 Supprime le paramètre param de la liste des paramètres
331 if param in self.params : self.params.remove(param)
332 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
334 def get_parametres_fonctions_avant_etape(self,etape):
336 Retourne deux éléments :
337 - une liste contenant les noms des paramètres (constantes ou EVAL)
339 - une liste contenant les formules définies avant etape
343 # on récupère le contexte avant etape
344 # on ne peut mettre dans les deux listes que des éléments de ce contexte
345 d=self.get_contexte_avant(etape)
346 # construction de l_constantes
347 for param in self.params:
349 if not nom : continue
350 if d.has_key(nom): l_constantes.append(nom)
351 # construction de l_fonctions
352 for form in self.fonctions:
354 if not nom : continue
355 if d.has_key(nom): l_fonctions.append(form.get_formule())
357 # on ajoute les concepts produits par DEFI_VALEUR
358 # XXX On pourrait peut etre faire plutot le test sur le type
359 # de concept : entier, reel, complexe, etc.
360 for k,v in d.items():
361 if hasattr(v,'etape') and v.etape.nom in ('DEFI_VALEUR',):
362 l_constantes.append(k)
364 # on retourne les deux listes
365 return l_constantes,l_fonctions
367 def get_nb_etapes_avant(self,niveau):
369 Retourne le nombre d etapes avant le debut de niveau
372 for niv in self.etapes_niveaux:
373 if niv == niveau:break
374 nb=nb+len(niv.etapes)
377 def send_message(self,message):
379 self.appli.send_message(message)
381 def init_modif(self):
383 Méthode appelée au moment où une modification va être faite afin de
384 déclencher d'éventuels traitements pré-modification
386 self.state = 'modified'
392 def get_liste_mc_inconnus(self):
394 Retourne une liste contenant les mots-clés inconnus à la relecture du JDC
396 # cette liste a le format suivant : [etape,(bloc,mcfact,...),nom_mc,valeur_mc]
398 for etape in self.etapes :
400 if not etape.isvalid() :
401 l = etape.get_liste_mc_inconnus()
402 if l : l_mc.extend(l)
405 def get_genealogie(self):
407 Retourne la liste des noms des ascendants de l'objet self
408 jusqu'à la première ETAPE parent.
412 def set_etape_context(self,etape):
414 Positionne l'etape qui sera utilisee dans NommerSdProd pour
415 decider si le concept passé pourra etre nommé
417 self._etape_context=etape
419 def reset_context(self):
421 Cette methode reinitialise le contexte glissant pour pouvoir
422 tenir compte des modifications de l'utilisateur : création
423 de commandes, nommage de concepts, etc.
425 self.current_context={}
426 self.index_etape_courante=0
428 def del_sdprod(self,sd):
430 Supprime la SD sd de la liste des sd et des dictionnaires de contexte
432 if sd in self.sds : self.sds.remove(sd)
433 if self.g_context.has_key(sd.nom) : del self.g_context[sd.nom]
434 if self.sds_dict.has_key(sd.nom) : del self.sds_dict[sd.nom]
436 def del_param(self,param):
438 Supprime le paramètre param de la liste des paramètres
441 if param in self.params : self.params.remove(param)
442 if self.g_context.has_key(param.nom) : del self.g_context[param.nom]
444 def del_fonction(self,fonction):
446 Supprime la fonction fonction de la liste des fonctions
449 if fonction in self.fonctions : self.fonctions.remove(fonction)
450 if self.g_context.has_key(fonction.nom) : del self.g_context[fonction.nom]
452 def append_sdprod(self,sd):
454 Ajoute la SD sd à la liste des sd en vérifiant au préalable qu'une SD de
455 même nom n'existe pas déjà
457 if sd == None or sd.nom == None:return
459 o=self.sds_dict.get(sd.nom,None)
460 if isinstance(o,ASSD):
461 raise AsException("Nom de concept deja defini : %s" % sd.nom)
462 self.sds_dict[sd.nom]=sd
463 self.g_context[sd.nom] = sd
464 if sd not in self.sds : self.sds.append(sd)
466 def append_param(self,param):
468 Ajoute le paramètre param à la liste des params
469 et au contexte global
471 # il faudrait vérifier qu'un paramètre de même nom n'existe pas déjà !!!
472 if param not in self.params : self.params.append(param)
473 self.g_context[param.nom]=param
475 def append_fonction(self,fonction):
477 Ajoute la fonction fonction à la liste des fonctions
478 et au contexte global
480 # il faudrait vérifier qu'une fonction de même nom n'existe pas déjà !!!
481 if fonction not in self.fonctions : self.fonctions.append(fonction)
482 self.g_context[fonction.nom]=fonction
484 def delete_concept(self,sd):
489 Mettre a jour les etapes du JDC suite à la disparition du
491 Seuls les mots cles simples MCSIMP font un traitement autre
492 que de transmettre aux fils
494 for etape in self.etapes :
495 etape.delete_concept(sd)
497 def replace_concept_after_etape(self,etape,old_sd,sd):
499 Met à jour les étapes du JDC qui sont après etape en fonction
500 du remplacement du concept sd
502 index = self.etapes.index(etape)+1
503 if index == len(self.etapes) :
504 return # etape est la dernière étape du jdc ...on ne fait rien !
505 for child in self.etapes[index:]:
506 child.replace_concept(old_sd,sd)
508 def dump_state(self):
510 print "JDC.state: ",self.state
511 for etape in self.etapes :
512 print etape.nom+".state: ",etape.state
514 def change_unit(self,unit,etape,old_unit):
515 if self.recorded_units.has_key(old_unit):del self.recorded_units[old_unit]
516 self.record_unit(unit,etape)
518 def record_unit(self,unit,etape):
519 """Enregistre les unites logiques incluses et les infos relatives a l'etape"""
522 self.recorded_units[None]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
524 self.recorded_units[unit]=(etape.fichier_ini ,etape.fichier_text,etape.recorded_units)
526 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
527 def register(self,etape):
529 Cette méthode ajoute etape dans la liste
530 des etapes self.etapes et retourne l identificateur d'étape
531 fourni par l appel a g_register
533 A quoi sert editmode ?
534 - Si editmode vaut 1, on est en mode edition de JDC. On cherche
535 à enregistrer une étape que l'on a créée avec eficas (en passant
536 par addentite) auquel cas on ne veut récupérer que son numéro
537 d'enregistrement et c'est addentité qui l'enregistre dans
538 self.etapes à la bonne place...
539 - Si editmode vaut 0, on est en mode relecture d'un fichier de
540 commandes et on doit enregistrer l'étape à la fin de self.etapes
541 (dans ce cas l'ordre des étapes est bien l'ordre chronologique
544 if not self.editmode:
545 self.etapes.append(etape)
548 return self.g_register(etape)
550 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
551 def NommerSdprod(self,sd,sdnom,restrict='non'):
553 Nomme la SD apres avoir verifie que le nommage est possible :
555 Si le nom est deja utilise, leve une exception
556 Met le concept créé dans le concept global g_context
558 # XXX En mode editeur dans EFICAS, le nommage doit etre géré différemment
559 # Le dictionnaire g_context ne représente pas le contexte
560 # effectif avant une étape.
561 # Il faut utiliser get_contexte_avant avec indication de l'étape
563 # Cette etape est indiquee par l'attribut _etape_context qui a ete
564 # positionné préalablement par un appel à set_etape_context
566 if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom
568 if self._etape_context:
569 o=self.get_contexte_avant(self._etape_context).get(sdnom,None)
571 o=self.sds_dict.get(sdnom,None)
573 if isinstance(o,ASSD):
574 raise AsException("Nom de concept deja defini : %s" % sdnom)
576 # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
577 # Ajoute a la creation (appel de reg_sd).
578 self.sds_dict[sdnom]=sd
581 # En plus si restrict vaut 'non', on insere le concept dans le contexte du JDC
582 if restrict == 'non':
583 self.g_context[sdnom]=sd
585 #ATTENTION SURCHARGE : cette methode doit etre gardée en synchronisation avec celle de Noyau
586 def delete_concept_after_etape(self,etape,sd):
588 Met à jour les étapes du JDC qui sont après etape en fonction
589 de la disparition du concept sd
591 index = self.etapes.index(etape)+1
592 if index == len(self.etapes) :
593 return # etape est la dernière étape du jdc ...on ne fait rien !
594 for child in self.etapes[index:]:
595 child.delete_concept(sd)
597 #ATTENTION SURCHARGE : les methodes ci-dessous surchargent des methodes de Noyau et Validation : a reintegrer