2 # Copyright (C) 2007-2013 EDF R&D
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License.
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 Ce module contient la classe MCCOMPO qui sert à factoriser les comportements
26 from __future__ import absolute_import
27 from __future__ import print_function
29 from . import N_OBJECT
32 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)
45 print(("MCCOMPO.build_mc ", self.nom))
46 # Dans la phase de reconstruction args peut contenir des mots-clés
47 # qui ne sont pas dans le dictionnaire des entites de definition (self.definition.entites)
48 # de l'objet courant (self)
49 # mais qui sont malgré tout des descendants de l'objet courant
56 # On recopie le dictionnaire des arguments pour protéger l'original des
57 # delete (del args[k])
61 # On construit les sous entites presentes ou obligatoires
62 # 1- les entites présentes dans les arguments et dans la définition
63 # 2- les entités non présentes dans les arguments, présentes dans la définition avec un défaut
64 # Phase 1.1 : on traite d'abord les SIMP pour enregistrer les mots cles
66 for k, v in list(self.definition.entites.items()):
69 if k in args or v.statut == 'o':
71 # Creation par appel de la methode __call__ de la definition de la sous entite k de self
72 # si une valeur existe dans args ou est obligatoire (generique si toutes les
73 # entites ont l attribut statut )
75 objet = v(val=args.get(k, None), nom=k, parent=self)
76 mc_liste.append(objet)
77 # Si l'objet a une position globale on l'ajoute aux listes
79 if hasattr(objet.definition, 'position'):
80 if objet.definition.position == 'global':
81 self.append_mc_global(objet)
82 elif objet.definition.position == 'global_jdc':
83 self.append_mc_global_jdc(objet)
87 # Phase 1.2 : on traite les autres entites que SIMP
88 # (FACT en fait car un BLOC ne peut avoir le meme nom qu'un mot-clef)
89 for k, v in list(self.definition.entites.items()):
92 if k in args or v.statut == 'o':
94 # Creation par appel de la methode __call__ de la definition de la sous entite k de self
95 # si une valeur existe dans args ou est obligatoire (generique si toutes les
96 # entites ont l attribut statut )
98 objet = v(val=args.get(k, None), nom=k, parent=self)
99 mc_liste.append(objet)
104 # On construit les objets (en général, blocs) conditionnés par les mots-clés précédemment créés.
105 # A ce stade, mc_liste ne contient que les fils de l'objet courant
106 # args ne contient plus que des mots-clés qui n'ont pas été attribués car ils sont
107 # à attribuer à des blocs du niveau inférieur ou bien sont des mots-clés erronés
108 for k, v in list(self.definition.entites.items()):
109 if v.label != 'BLOC':
111 # condition and a or b : Equivalent de l'expression : condition ?
114 #PNPN on recalcule dico_valeurs dans le for
115 # pour les globaux imbriques (exple Telemac Advection)
116 # avant le calcul etait avant le for
117 dico_valeurs = self.cree_dict_condition(mc_liste, condition=1)
118 globs = self.jdc and self.jdc.condition_context or {}
119 if v.verif_presence(dico_valeurs, globs):
120 # Si le bloc existe :
122 # 2- on l'ajoute à mc_liste
123 # 3- on récupère les arguments restant
124 # 4- on reconstruit le dictionnaire équivalent à mc_liste
125 bloc = v(nom=k, val=args, parent=self)
126 mc_liste.append(bloc)
127 args = bloc.reste_val
128 # On ne recalcule pas le contexte car on ne tient pas compte des blocs
129 # pour évaluer les conditions de présence des blocs
130 # dico_valeurs = self.cree_dict_valeurs(mc_liste)
132 # On conserve les arguments superflus dans l'attribut reste_val
133 self.reste_val = args
134 # On ordonne la liste ainsi créée suivant l'ordre du catalogue
135 # (utile seulement pour IHM graphique)
136 mc_liste = self.ordonne_liste(mc_liste)
137 # on retourne la liste ainsi construite
140 def ordonne_liste(self, mc_liste):
142 Ordonne la liste suivant l'ordre du catalogue.
143 Seulement pour IHM graphique
145 if self.jdc and self.jdc.cata_ordonne_dico != None:
146 liste_noms_mc_ordonnee = self.get_liste_mc_ordonnee_brute(
147 self.get_genealogie(), self.jdc.cata_ordonne_dico)
148 return self.ordonne_liste_mc(mc_liste, liste_noms_mc_ordonnee)
152 def cree_dict_valeurs(self, liste=[], condition=0):
154 Cette méthode crée un contexte (sous la forme d'un dictionnaire)
155 à partir des valeurs des mots clés contenus dans l'argument liste.
156 L'opération consiste à parcourir la liste (d'OBJECT) et à la
157 transformer en un dictionnaire dont les clés sont les noms des
158 mots clés et les valeurs dépendent du type d'OBJECT.
159 Ce dictionnaire servira de liste d'arguments d'appel pour les
160 fonctions sd_prod de commandes et ops de macros ou de contexte
161 d'évaluation des conditions de présence de BLOC.
163 Si l'argument condition de la méthode vaut 1, on ne
164 remonte pas les valeurs des mots clés contenus dans des blocs
165 pour eviter les bouclages.
167 Cette méthode réalise les opérations suivantes en plus de transformer
168 la liste en dictionnaire :
170 - ajouter tous les mots-clés non présents avec la valeur None
171 - ajouter tous les mots-clés globaux (attribut position = 'global'
174 L'argument liste est, en général, une mc_liste en cours de
175 construction, contenant les mots-clés locaux et les blocs déjà créés.
181 # Si v est un BLOC, on inclut ses items dans le dictionnaire
182 # représentatif du contexte. Les blocs sont retournés par get_valeur
183 # sous la forme d'un dictionnaire : les mots-clés fils de blocs sont
184 # donc remontés au niveau du contexte.
186 dadd = v.get_valeur()
187 assert intersection_vide(dico, dadd)
190 assert not v.nom in dico, "deja vu : %s" % v.nom
191 dico[v.nom] = v.get_valeur()
193 # On rajoute tous les autres mots-clés locaux possibles avec la valeur
195 # Pour les mots-clés facteurs, on ne traite que ceux avec statut défaut ('d')
197 # On n'ajoute aucune information sur les blocs. Ils n'ont pas de défaut seulement
199 # XXX remplacer le not has_key par un dico différent et faire dico2.update(dico)
200 # ce n'est qu'un pb de perf
201 for k, v in list(self.definition.entites.items()):
203 if v.label == 'SIMP':
206 elif v.label == 'FACT':
207 if v.statut in ('c', 'd'):
208 # Mot clé facteur avec défaut ou caché provisoire
209 dico[k] = v(val=None, nom=k, parent=self)
210 # On demande la suppression des pointeurs arrieres
211 # pour briser les eventuels cycles
215 # A ce stade on a rajouté tous les mots-clés locaux possibles (fils directs) avec leur
216 # valeur par défaut ou la valeur None
218 # On rajoute les mots-clés globaux sans écraser les clés existantes
219 dico_mc = self.recherche_mc_globaux()
225 def cree_dict_toutes_valeurs(self):
226 """Semblable à `cree_dict_valeurs(liste=self.mc_liste)` en supprimant les
228 dico = self.cree_dict_valeurs(self.mc_liste, condition=0)
229 dico = dict([(k, v) for k, v in list(dico.items()) if v is not None])
232 def cree_dict_condition(self, liste=[], condition=0):
234 Methode pour construire un contexte qui servira dans l'évaluation
235 des conditions de présence de blocs. Si une commande a un concept
236 produit réutilisé, on ajoute la clé 'reuse'
238 dico = self.cree_dict_valeurs(liste, condition=1)
239 # On ajoute la cle "reuse" pour les MCCOMPO qui ont un attribut reuse. A destination
240 # uniquement des commandes. Ne devrait pas etre dans cette classe mais
241 # dans une classe dérivée
242 if not 'reuse' in dico and hasattr(self, 'reuse'):
243 dico['reuse'] = self.reuse
246 def recherche_mc_globaux(self):
248 Retourne la liste des mots-clés globaux de l'étape à laquelle appartient self
249 et des mots-clés globaux du jdc
251 etape = self.get_etape()
253 dict_mc_globaux_fac = self.recherche_mc_globaux_facultatifs()
254 for k, v in list(etape.mc_globaux.items()):
255 dict_mc_globaux_fac[k] = v.get_valeur()
257 for k, v in list(self.jdc.mc_globaux.items()):
258 dict_mc_globaux_fac[k] = v.get_valeur()
259 return dict_mc_globaux_fac
263 def recherche_mc_globaux_facultatifs(self):
265 Cette méthode interroge la définition de self et retourne la liste des mots-clés fils
266 directs de self de type 'global'.
267 position='global' n'est donc possible (et n'a de sens) qu'au plus haut niveau.
270 etape = self.get_etape()
273 for k, v in list(etape.definition.entites.items()):
274 if v.label != 'SIMP':
276 if v.position != 'global':
280 obj = v(val=None, nom=k, parent=etape)
281 dico[k] = obj.get_valeur()
286 Méthode qui supprime toutes les références arrières afin que l'objet puisse
287 etre correctement détruit par le garbage collector
289 N_OBJECT.OBJECT.supprime(self)
290 for child in self.mc_liste:
293 def __getitem__(self, key):
295 Cette méthode retourne la valeur d'un sous mot-clé (key)
297 return self.get_mocle(key)
299 def get_mocle(self, key):
301 Retourne la valeur du sous mot-clé key
302 Ce sous mot-clé peut exister, avoir une valeur par defaut ou etre
303 dans un BLOC fils de self
305 # on cherche dans les mots cles presents, le mot cle de nom key
306 # s'il est là on retourne sa valeur (méthode get_val)
307 for child in self.mc_liste:
309 return child.get_valeur()
310 # Si on n a pas trouve de mot cle present on retourne le defaut
311 # eventuel pour les mots cles accessibles dans la definition
314 d = self.definition.entites[key]
315 if d.label == 'SIMP':
317 elif d.label == 'FACT':
318 # il faut construire les objets necessaires pour
319 # evaluer les conditions des blocs eventuels (a faire)
322 if d.statut != 'c' and d.statut != 'd':
325 return d(val=None, nom=key, parent=self)
327 # le mot cle n est pas defini a ce niveau
329 # Si on a toujours rien trouve, on cherche dans les blocs presents
330 # On suppose que tous les blocs possibles ont ete crees meme ceux
331 # induits par un mot cle simple absent avec defaut (???)
332 for mc in self.mc_liste:
336 return mc.get_mocle(key)
338 # On n a rien trouve dans ce bloc, on passe au suivant
340 # On a rien trouve, le mot cle est absent.
341 # On leve une exception
342 raise IndexError("Le mot cle %s n existe pas dans %s" % (key, self))
344 def get_child(self, name, restreint='non'):
346 Retourne le fils de self de nom name ou None s'il n'existe pas
347 Si restreint vaut oui : ne regarde que dans la mc_liste
348 Si restreint vaut non : regarde aussi dans les entites possibles
349 avec defaut (Ce dernier cas n'est utilisé que dans le catalogue)
351 for v in self.mc_liste:
354 if restreint == 'non':
356 entite = self.definition.entites[name]
357 if entite.label == 'SIMP' or (entite.label == 'FACT' and entite.statut in ('c', 'd')):
358 return entite(None, name, None)
364 def append_mc_global(self, mc):
366 Ajoute le mot-clé mc à la liste des mots-clés globaux de l'étape
368 etape = self.get_etape()
371 etape.mc_globaux[nom] = mc
373 def append_mc_global_jdc(self, mc):
375 Ajoute le mot-clé mc à la liste des mots-clés globaux du jdc
378 self.jdc.mc_globaux[nom] = mc
381 """ Retourne une copie de self """
382 objet = self.makeobjet()
383 # FR : attention !!! avec makeobjet, objet a le meme parent que self
384 # ce qui n'est pas du tout bon dans le cas d'une copie !!!!!!!
385 # FR : peut-on passer par là autrement que dans le cas d'une copie ???
386 # FR --> je suppose que non
387 # XXX CCAR : le pb c'est qu'on vérifie ensuite quel parent avait l'objet
388 # Il me semble preferable de changer le parent a la fin quand la copie
390 objet.valeur = copy(self.valeur)
391 objet.val = copy(self.val)
393 for obj in self.mc_liste:
395 new_obj.reparent(objet)
396 objet.mc_liste.append(new_obj)
399 def reparent(self, parent):
401 Cette methode sert a reinitialiser la parente de l'objet
404 self.jdc = parent.get_jdc_root()
405 self.etape = parent.etape
406 for mocle in self.mc_liste:
409 def get_sd_utilisees(self):
411 Retourne la liste des concepts qui sont utilisés à l'intérieur de self
412 ( comme valorisation d'un MCS)
415 for child in self.mc_liste:
416 l.extend(child.get_sd_utilisees())
419 def get_sd_mcs_utilisees(self):
421 Retourne la ou les SD utilisée par self sous forme d'un dictionnaire :
422 - Si aucune sd n'est utilisée, le dictionnaire est vide.
423 - Sinon, les clés du dictionnaire sont les mots-clés derrière lesquels on
424 trouve des sd ; la valeur est la liste des sd attenante.
427 { 'VALE_F': [ <Cata.cata.fonction_sdaster instance at 0x9419854>,
428 <Cata.cata.fonction_sdaster instance at 0x941a204> ],
429 'MODELE': [<Cata.cata.modele instance at 0x941550c>] }
432 for child in self.mc_liste:
433 daux = child.get_sd_mcs_utilisees()
435 dico[cle] = dico.get(cle, [])
436 dico[cle].extend(daux[cle])
439 def get_mcs_with_co(self, co):
441 Cette methode retourne l'objet MCSIMP fils de self
442 qui a le concept co comme valeur.
443 En principe, elle ne doit etre utilisee que pour les concepts
444 instances de la classe CO
447 for child in self.mc_liste:
448 l.extend(child.get_mcs_with_co(co))
451 def get_all_co(self):
453 Cette methode retourne tous les concepts instances de CO
456 for child in self.mc_liste:
457 l.extend(child.get_all_co())
461 def intersection_vide(dict1, dict2):
462 """Verification qu'il n'y a pas de clé commune entre 'dict1' et 'dict2'."""
465 inter = sk1.intersection(sk2)
468 print(('ERREUR: Mot(s)-clef(s) vu(s) plusieurs fois :', tuple(inter)))