1 #@ MODIF N_MCCOMPO Noyau DATE 30/08/2011 AUTEUR COURTOIS M.COURTOIS
2 # -*- coding: iso-8859-1 -*-
3 # RESPONSABLE COURTOIS M.COURTOIS
4 # CONFIGURATION MANAGEMENT OF EDF VERSION
5 # ======================================================================
6 # COPYRIGHT (C) 1991 - 2011 EDF R&D WWW.CODE-ASTER.ORG
7 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
8 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
9 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
10 # (AT YOUR OPTION) ANY LATER VERSION.
12 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
13 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
14 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
15 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
17 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
18 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
19 # 1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
22 # ======================================================================
26 Ce module contient la classe MCCOMPO qui sert à factoriser les comportements
33 class MCCOMPO(N_OBJECT.OBJECT):
35 Classe support d'un OBJECT composite
41 Construit la liste des sous-entites du MCCOMPO
42 à partir du dictionnaire des arguments (valeur)
44 if CONTEXT.debug : print "MCCOMPO.build_mc ",self.nom
45 # Dans la phase de reconstruction args peut contenir des mots-clés
46 # qui ne sont pas dans le dictionnaire des entites de definition (self.definition.entites)
47 # de l'objet courant (self)
48 # mais qui sont malgré tout des descendants de l'objet courant (petits-fils, ...)
50 if args == None : args ={}
53 # On recopie le dictionnaire des arguments pour protéger l'original des delete (del args[k])
57 # On construit les sous entites presentes ou obligatoires
58 # 1- les entites présentes dans les arguments et dans la définition
59 # 2- les entités non présentes dans les arguments, présentes dans la définition avec un défaut
60 # Phase 1.1 : on traite d'abord les SIMP pour enregistrer les mots cles globaux
61 for k,v in self.definition.entites.items():
62 if v.label != 'SIMP':continue
63 if args.has_key(k) or v.statut=='o' :
65 # Creation par appel de la methode __call__ de la definition de la sous entite k de self
66 # si une valeur existe dans args ou est obligatoire (generique si toutes les
67 # entites ont l attribut statut )
69 objet=v(val=args.get(k,None),nom=k,parent=self)
70 mc_liste.append(objet)
71 # Si l'objet a une position globale on l'ajoute aux listes correspondantes
72 if hasattr(objet.definition,'position'):
73 if objet.definition.position == 'global' :
74 self.append_mc_global(objet)
75 elif objet.definition.position == 'global_jdc' :
76 self.append_mc_global_jdc(objet)
80 # Phase 1.2 : on traite les autres entites que SIMP
81 # (FACT en fait car un BLOC ne peut avoir le meme nom qu'un mot-clef)
82 for k,v in self.definition.entites.items():
83 if v.label == 'SIMP':continue
84 if args.has_key(k) or v.statut=='o' :
86 # Creation par appel de la methode __call__ de la definition de la sous entite k de self
87 # si une valeur existe dans args ou est obligatoire (generique si toutes les
88 # entites ont l attribut statut )
90 objet=v(val=args.get(k,None),nom=k,parent=self)
91 mc_liste.append(objet)
96 # On construit les objets (en général, blocs) conditionnés par les mots-clés précédemment créés.
97 # A ce stade, mc_liste ne contient que les fils de l'objet courant
98 # args ne contient plus que des mots-clés qui n'ont pas été attribués car ils sont
99 # à attribuer à des blocs du niveau inférieur ou bien sont des mots-clés erronés
100 dico_valeurs = self.cree_dict_condition(mc_liste,condition=1)
101 for k,v in self.definition.entites.items():
102 if v.label != 'BLOC':continue
103 # condition and a or b : Equivalent de l'expression : condition ? a : b du langage C
104 globs= self.jdc and self.jdc.condition_context or {}
105 if v.verif_presence(dico_valeurs,globs):
106 # Si le bloc existe :
108 # 2- on l'ajoute à mc_liste
109 # 3- on récupère les arguments restant
110 # 4- on reconstruit le dictionnaire équivalent à mc_liste
111 bloc = v(nom=k,val=args,parent=self)
112 mc_liste.append(bloc)
114 # On ne recalcule pas le contexte car on ne tient pas compte des blocs
115 # pour évaluer les conditions de présence des blocs
116 #dico_valeurs = self.cree_dict_valeurs(mc_liste)
118 # On conserve les arguments superflus dans l'attribut reste_val
120 # On ordonne la liste ainsi créée suivant l'ordre du catalogue
121 # (utile seulement pour IHM graphique)
122 mc_liste = self.ordonne_liste(mc_liste)
123 # on retourne la liste ainsi construite
126 def ordonne_liste(self,mc_liste):
128 Ordonne la liste suivant l'ordre du catalogue.
129 Seulement pour IHM graphique
131 if self.jdc and self.jdc.cata_ordonne_dico != None :
132 liste_noms_mc_ordonnee = self.get_liste_mc_ordonnee_brute(
133 self.get_genealogie(),self.jdc.cata_ordonne_dico)
134 return self.ordonne_liste_mc(mc_liste,liste_noms_mc_ordonnee)
138 def cree_dict_valeurs(self,liste=[],condition=0):
140 Cette méthode crée un contexte (sous la forme d'un dictionnaire)
141 à partir des valeurs des mots clés contenus dans l'argument liste.
142 L'opération consiste à parcourir la liste (d'OBJECT) et à la
143 transformer en un dictionnaire dont les clés sont les noms des
144 mots clés et les valeurs dépendent du type d'OBJECT.
145 Ce dictionnaire servira de liste d'arguments d'appel pour les
146 fonctions sd_prod de commandes et ops de macros ou de contexte
147 d'évaluation des conditions de présence de BLOC.
149 Si l'argument condition de la méthode vaut 1, on ne
150 remonte pas les valeurs des mots clés contenus dans des blocs
151 pour eviter les bouclages.
153 Cette méthode réalise les opérations suivantes en plus de transformer
154 la liste en dictionnaire :
156 - ajouter tous les mots-clés non présents avec la valeur None
157 - ajouter tous les mots-clés globaux (attribut position = 'global'
160 L'argument liste est, en général, une mc_liste en cours de
161 construction, contenant les mots-clés locaux et les blocs déjà créés.
167 # Si v est un BLOC, on inclut ses items dans le dictionnaire
168 # représentatif du contexte. Les blocs sont retournés par get_valeur
169 # sous la forme d'un dictionnaire : les mots-clés fils de blocs sont
170 # donc remontés au niveau du contexte.
172 dadd = v.get_valeur()
173 assert intersection_vide(dico, dadd)
176 assert not dico.has_key(v.nom), "deja vu : %s" % v.nom
177 dico[v.nom]=v.get_valeur()
179 # On rajoute tous les autres mots-clés locaux possibles avec la valeur
181 # Pour les mots-clés facteurs, on ne traite que ceux avec statut défaut ('d')
183 # On n'ajoute aucune information sur les blocs. Ils n'ont pas de défaut seulement
185 #XXX remplacer le not has_key par un dico différent et faire dico2.update(dico)
186 # ce n'est qu'un pb de perf
187 for k,v in self.definition.entites.items():
188 if not dico.has_key(k):
189 if v.label == 'SIMP':
192 elif v.label == 'FACT' :
193 if v.statut in ('c','d') :
194 # Mot clé facteur avec défaut ou caché provisoire
195 dico[k]=v(val=None,nom=k,parent=self)
196 # On demande la suppression des pointeurs arrieres
197 # pour briser les eventuels cycles
201 # A ce stade on a rajouté tous les mots-clés locaux possibles (fils directs) avec leur
202 # valeur par défaut ou la valeur None
204 # On rajoute les mots-clés globaux sans écraser les clés existantes
205 dico_mc = self.recherche_mc_globaux()
211 def cree_dict_condition(self,liste=[],condition=0):
213 Methode pour construire un contexte qui servira dans l'évaluation
214 des conditions de présence de blocs. Si une commande a un concept
215 produit réutilisé, on ajoute la clé 'reuse'
217 dico=self.cree_dict_valeurs(liste,condition=1)
218 # On ajoute la cle "reuse" pour les MCCOMPO qui ont un attribut reuse. A destination
219 # uniquement des commandes. Ne devrait pas etre dans cette classe mais dans une classe dérivée
220 if not dico.has_key('reuse') and hasattr(self,'reuse'):
221 dico['reuse']=self.reuse
224 def recherche_mc_globaux(self):
226 Retourne la liste des mots-clés globaux de l'étape à laquelle appartient self
227 et des mots-clés globaux du jdc
229 etape = self.get_etape()
231 dict_mc_globaux_fac = self.recherche_mc_globaux_facultatifs()
232 for k,v in etape.mc_globaux.items():
233 dict_mc_globaux_fac[k]=v.get_valeur()
235 for k,v in self.jdc.mc_globaux.items():
236 dict_mc_globaux_fac[k]=v.get_valeur()
237 return dict_mc_globaux_fac
241 def recherche_mc_globaux_facultatifs(self):
243 Cette méthode interroge la définition de self et retourne la liste des mots-clés fils
244 directs de self de type 'global'.
245 position='global' n'est donc possible (et n'a de sens) qu'au plus haut niveau.
248 etape = self.get_etape()
249 if not etape : return {}
250 for k,v in etape.definition.entites.items():
251 if v.label != 'SIMP' : continue
252 if v.position != 'global' : continue
253 if v.statut == 'o':continue
254 obj = v(val=None,nom=k,parent=etape)
255 dico[k]=obj.get_valeur()
260 Méthode qui supprime toutes les références arrières afin que l'objet puisse
261 etre correctement détruit par le garbage collector
263 N_OBJECT.OBJECT.supprime(self)
264 for child in self.mc_liste :
267 def __getitem__(self,key):
269 Cette méthode retourne la valeur d'un sous mot-clé (key)
271 return self.get_mocle(key)
273 def get_mocle(self,key):
275 Retourne la valeur du sous mot-clé key
276 Ce sous mot-clé peut exister, avoir une valeur par defaut ou etre
277 dans un BLOC fils de self
279 # on cherche dans les mots cles presents, le mot cle de nom key
280 # s'il est là on retourne sa valeur (méthode get_val)
281 for child in self.mc_liste:
282 if child.nom == key : return child.get_val()
283 # Si on n a pas trouve de mot cle present on retourne le defaut
284 # eventuel pour les mots cles accessibles dans la definition
287 d=self.definition.entites[key]
288 if d.label == 'SIMP':
290 elif d.label == 'FACT':
291 # il faut construire les objets necessaires pour
292 # evaluer les conditions des blocs eventuels (a faire)
293 if d.statut == 'o' :return None
294 if d.statut != 'c' and d.statut != 'd' :
297 return d(val=None,nom=key,parent=self)
299 # le mot cle n est pas defini a ce niveau
301 # Si on a toujours rien trouve, on cherche dans les blocs presents
302 # On suppose que tous les blocs possibles ont ete crees meme ceux
303 # induits par un mot cle simple absent avec defaut (???)
304 for mc in self.mc_liste :
305 if not mc.isBLOC() : continue
307 return mc.get_mocle(key)
309 # On n a rien trouve dans ce bloc, on passe au suivant
311 # On a rien trouve, le mot cle est absent.
312 # On leve une exception
313 raise IndexError,"Le mot cle %s n existe pas dans %s" % (key,self)
315 def get_child(self,name,restreint = 'non'):
317 Retourne le fils de self de nom name ou None s'il n'existe pas
318 Si restreint vaut oui : ne regarde que dans la mc_liste
319 Si restreint vaut non : regarde aussi dans les entites possibles
320 avec defaut (Ce dernier cas n'est utilisé que dans le catalogue)
322 for v in self.mc_liste:
323 if v.nom == name : return v
324 if restreint == 'non' :
326 entite=self.definition.entites[name]
327 if entite.label == 'SIMP' or (entite.label == 'FACT' and entite.statut in ( 'c', 'd')):
328 return entite(None,name,None)
334 def append_mc_global(self,mc):
336 Ajoute le mot-clé mc à la liste des mots-clés globaux de l'étape
338 etape = self.get_etape()
341 etape.mc_globaux[nom]=mc
343 def append_mc_global_jdc(self,mc):
345 Ajoute le mot-clé mc à la liste des mots-clés globaux du jdc
348 self.jdc.mc_globaux[nom]=mc
351 """ Retourne une copie de self """
352 objet = self.makeobjet()
353 # FR : attention !!! avec makeobjet, objet a le meme parent que self
354 # ce qui n'est pas du tout bon dans le cas d'une copie !!!!!!!
355 # FR : peut-on passer par là autrement que dans le cas d'une copie ???
356 # FR --> je suppose que non
357 # XXX CCAR : le pb c'est qu'on vérifie ensuite quel parent avait l'objet
358 # Il me semble preferable de changer le parent a la fin quand la copie est acceptee
359 objet.valeur = copy(self.valeur)
360 objet.val = copy(self.val)
362 for obj in self.mc_liste:
364 new_obj.reparent(objet)
365 objet.mc_liste.append(new_obj)
368 def reparent(self,parent):
370 Cette methode sert a reinitialiser la parente de l'objet
373 self.jdc=parent.get_jdc_root()
374 self.etape=parent.etape
375 for mocle in self.mc_liste:
378 def get_sd_utilisees(self):
380 Retourne la liste des concepts qui sont utilisés à l'intérieur de self
381 ( comme valorisation d'un MCS)
384 for child in self.mc_liste:
385 l.extend(child.get_sd_utilisees())
388 def get_sd_mcs_utilisees(self):
390 Retourne la ou les SD utilisée par self sous forme d'un dictionnaire :
391 - Si aucune sd n'est utilisée, le dictionnaire est vide.
392 - Sinon, les clés du dictionnaire sont les mots-clés derrière lesquels on
393 trouve des sd ; la valeur est la liste des sd attenante.
396 { 'VALE_F': [ <Cata.cata.para_sensi instance at 0x9419854>,
397 <Cata.cata.para_sensi instance at 0x941a204> ],
398 'MODELE': [<Cata.cata.modele instance at 0x941550c>] }
401 for child in self.mc_liste:
402 daux = child.get_sd_mcs_utilisees()
403 for cle in daux.keys():
404 dico[cle] = dico.get(cle, [])
405 dico[cle].extend(daux[cle])
408 def get_mcs_with_co(self,co):
410 Cette methode retourne l'objet MCSIMP fils de self
411 qui a le concept co comme valeur.
412 En principe, elle ne doit etre utilisee que pour les concepts
413 instances de la classe CO
416 for child in self.mc_liste:
417 l.extend(child.get_mcs_with_co(co))
420 def get_all_co(self):
422 Cette methode retourne tous les concepts instances de CO
425 for child in self.mc_liste:
426 l.extend(child.get_all_co())
430 def intersection_vide(dict1, dict2):
431 """Verification qu'il n'y a pas de clé commune entre 'dict1' et 'dict2'."""
432 sk1 = set(dict1.keys())
433 sk2 = set(dict2.keys())
434 inter = sk1.intersection(sk2)
437 print 'ERREUR: Mot(s)-clef(s) vu(s) plusieurs fois :', tuple(inter)