2 # Copyright (C) 2007-2017 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)
46 #traceback.print_stack()
47 #print(("MCCOMPO.buildMc _____________________________________", self.nom))
48 #print (self.dicoPyxbDeConstruction)
50 print(("MCCOMPO.buildMc ", self.nom))
51 # Dans la phase de reconstruction args peut contenir des mots-clés
52 # qui ne sont pas dans le dictionnaire des entites de definition (self.definition.entites)
53 # de l'objet courant (self)
54 # mais qui sont malgré tout des descendants de l'objet courant
57 if args == None: args = {}
61 # On recopie le dictionnaire des arguments pour protéger l'original des
62 # delete (del args[k])
66 # On construit les sous entites presentes ou obligatoires
67 # 1- les entites présentes dans les arguments et dans la définition
68 # 2- les entités non présentes dans les arguments, présentes dans la définition avec un défaut
69 # Phase 1.1 : on traite d'abord les SIMP pour enregistrer les mots cles
71 # PN ligne suivante uniquement pour commodite
72 # a detruire quand cela fonctionne recursivement
73 if not hasattr(self, 'dicoPyxbDeConstruction') : self.dicoPyxbDeConstruction = {}
74 for k, v in list(self.definition.entites.items()):
77 if k in args or v.statut == 'o':
79 # Creation par appel de la methode __call__ de la definition de la sous entite k de self
80 # si une valeur existe dans args ou est obligatoire (generique si toutes les
81 # entites ont l attribut statut )
83 if self.dicoPyxbDeConstruction and k in self.dicoPyxbDeConstruction :
84 objPyxbDeConstruction=self.dicoPyxbDeConstruction[k]
85 del self.dicoPyxbDeConstruction[k]
87 objPyxbDeConstruction=None
88 objet = v(val=args.get(k, None), nom=k, parent=self,objPyxbDeConstruction=objPyxbDeConstruction)
90 # Si l'objet a une position globale on l'ajoute aux listes
92 if hasattr(objet.definition, 'position'):
93 if objet.definition.position == 'global':
94 self.append_mc_global(objet)
95 elif objet.definition.position == 'global_jdc':
96 self.append_mc_global_jdc(objet)
100 # Phase 1.2 : on traite les autres entites que SIMP
101 # (FACT en fait car un BLOC ne peut avoir le meme nom qu'un mot-clef)
102 for k, v in list(self.definition.entites.items()):
103 if v.label == 'SIMP':
105 if k in args or v.statut == 'o':
107 # Creation par appel de la methode __call__ de la definition de la sous entite k de self
108 # si une valeur existe dans args ou est obligatoire (generique si toutes les
109 # entites ont l attribut statut )
111 if self.dicoPyxbDeConstruction and k in self.dicoPyxbDeConstruction :
112 dicoPyxbDeConstruction=self.dicoPyxbDeConstruction[k]
113 del self.dicoPyxbDeConstruction[k]
115 dicoPyxbDeConstruction=None
116 objet = v(val=args.get(k, None), nom=k, parent=self,dicoPyxbDeConstruction=dicoPyxbDeConstruction)
117 mcListe.append(objet)
122 # On construit les objets (en général, blocs) conditionnés par les mots-clés précédemment créés.
123 # A ce stade, mcListe ne contient que les fils de l'objet courant
124 # args ne contient plus que des mots-clés qui n'ont pas été attribués car ils sont
125 # à attribuer à des blocs du niveau inférieur ou bien sont des mots-clés erronés
126 for k, v in list(self.definition.entites.items()):
127 if v.label != 'BLOC':
129 # condition and a or b : Equivalent de l'expression : condition ?
132 #PNPN on recalcule dico_valeurs dans le for
133 # pour les globaux imbriques (exple Telemac Advection)
134 # avant le calcul etait avant le for
135 dico_valeurs = self.creeDictCondition(mcListe, condition=1)
136 globs = self.jdc and self.jdc.condition_context or {}
137 if v.verifPresence(dico_valeurs, globs):
138 # Si le bloc existe :
140 # 2- on l'ajoute à mcListe
141 # 3- on récupère les arguments restant
142 # 4- on reconstruit le dictionnaire équivalent à mcListe
143 bloc = v(nom=k, val=args, parent=self,dicoPyxbDeConstruction=self.dicoPyxbDeConstruction)
145 args = bloc.reste_val
146 # On ne recalcule pas le contexte car on ne tient pas compte des blocs
147 # pour évaluer les conditions de présence des blocs
148 # dico_valeurs = self.creeDictValeurs(mcListe)
150 # On conserve les arguments superflus dans l'attribut reste_val
151 self.reste_val = args
152 # On ordonne la liste ainsi créée suivant l'ordre du catalogue
153 # (utile seulement pour IHM graphique)
154 mcListe = self.ordonneListe(mcListe)
155 # on retourne la liste ainsi construite
156 if self.jdc : self.cata=self.jdc.cata
157 else : self.cata = None
158 #self.buildObjPyxb(mcListe)
159 #else : print ('pas de construction pour ', self.nom, self.objPyxbDeConstruction)
160 #print ('buildObjPyxb : ' , self.nom)
161 #print(("MCCOMPO.buildMc fin_____________________________________", self.nom))
164 def ordonneListe(self, mcListe):
166 Ordonne la liste suivant l'ordre du catalogue.
167 Seulement pour IHM graphique
169 if self.jdc and self.jdc.cata_ordonne_dico != None:
170 liste_noms_mc_ordonnee = self.getListeMcOrdonneeBrute(
171 self.getGenealogie(), self.jdc.cata_ordonne_dico)
172 return self.ordonneListeMc(mcListe, liste_noms_mc_ordonnee)
176 def creeDictValeurs(self, liste=[], condition=0):
178 Cette méthode crée un contexte (sous la forme d'un dictionnaire)
179 à partir des valeurs des mots clés contenus dans l'argument liste.
180 L'opération consiste à parcourir la liste (d'OBJECT) et à la
181 transformer en un dictionnaire dont les clés sont les noms des
182 mots clés et les valeurs dépendent du type d'OBJECT.
183 Ce dictionnaire servira de liste d'arguments d'appel pour les
184 fonctions sd_prod de commandes et ops de macros ou de contexte
185 d'évaluation des conditions de présence de BLOC.
187 Si l'argument condition de la méthode vaut 1, on ne
188 remonte pas les valeurs des mots clés contenus dans des blocs
189 pour eviter les bouclages.
191 Cette méthode réalise les opérations suivantes en plus de transformer
192 la liste en dictionnaire :
194 - ajouter tous les mots-clés non présents avec la valeur None
195 - ajouter tous les mots-clés globaux (attribut position = 'global'
198 L'argument liste est, en général, une mcListe en cours de
199 construction, contenant les mots-clés locaux et les blocs déjà créés.
205 # Si v est un BLOC, on inclut ses items dans le dictionnaire
206 # représentatif du contexte. Les blocs sont retournés par getValeur
207 # sous la forme d'un dictionnaire : les mots-clés fils de blocs sont
208 # donc remontés au niveau du contexte.
211 assert intersection_vide(dico, dadd)
214 assert not v.nom in dico, "deja vu : %s" % v.nom
215 dico[v.nom] = v.getValeur()
217 # On rajoute tous les autres mots-clés locaux possibles avec la valeur
219 # Pour les mots-clés facteurs, on ne traite que ceux avec statut défaut ('d')
221 # On n'ajoute aucune information sur les blocs. Ils n'ont pas de défaut seulement
223 # XXX remplacer le not has_key par un dico différent et faire dico2.update(dico)
224 # ce n'est qu'un pb de perf
225 for k, v in list(self.definition.entites.items()):
227 if v.label == 'SIMP':
230 elif v.label == 'FACT':
231 if v.statut in ('c', 'd'):
232 # Mot clé facteur avec défaut ou caché provisoire
233 dico[k] = v(val=None, nom=k, parent=self)
234 # On demande la suppression des pointeurs arrieres
235 # pour briser les eventuels cycles
239 # A ce stade on a rajouté tous les mots-clés locaux possibles (fils directs) avec leur
240 # valeur par défaut ou la valeur None
242 # On rajoute les mots-clés globaux sans écraser les clés existantes
243 dico_mc = self.rechercheMcGlobaux()
249 def creeDictToutesValeurs(self):
250 """Semblable à `creeDictValeurs(liste=self.mcListe)` en supprimant les
252 dico = self.creeDictValeurs(self.mcListe, condition=0)
253 dico = dict([(k, v) for k, v in list(dico.items()) if v is not None])
256 def creeDictCondition(self, liste=[], condition=0):
258 Methode pour construire un contexte qui servira dans l'évaluation
259 des conditions de présence de blocs. Si une commande a un concept
260 produit réutilisé, on ajoute la clé 'reuse'
262 dico = self.creeDictValeurs(liste, condition=1)
263 # On ajoute la cle "reuse" pour les MCCOMPO qui ont un attribut reuse. A destination
264 # uniquement des commandes. Ne devrait pas etre dans cette classe mais
265 # dans une classe dérivée
266 if not 'reuse' in dico and hasattr(self, 'reuse'):
267 dico['reuse'] = self.reuse
270 def rechercheMcGlobaux(self):
272 Retourne la liste des mots-clés globaux de l'étape à laquelle appartient self
273 et des mots-clés globaux du jdc
275 etape = self.getEtape()
277 dict_mc_globaux_fac = self.rechercheMcGlobauxFacultatifs()
278 for k, v in list(etape.mc_globaux.items()):
279 dict_mc_globaux_fac[k] = v.getValeur()
281 for k, v in list(self.jdc.mc_globaux.items()):
282 dict_mc_globaux_fac[k] = v.getValeur()
283 return dict_mc_globaux_fac
287 def rechercheMcGlobauxFacultatifs(self):
289 Cette méthode interroge la définition de self et retourne la liste des mots-clés fils
290 directs de self de type 'global'.
291 position='global' n'est donc possible (et n'a de sens) qu'au plus haut niveau.
294 etape = self.getEtape()
297 for k, v in list(etape.definition.entites.items()):
298 if v.label != 'SIMP':
300 if v.position != 'global':
304 obj = v(val=None, nom=k, parent=etape)
305 dico[k] = obj.getValeur()
310 Méthode qui supprime toutes les références arrières afin que l'objet puisse
311 etre correctement détruit par le garbage collector
313 N_OBJECT.OBJECT.supprime(self)
314 for child in self.mcListe:
317 def __getitem__(self, key):
319 Cette méthode retourne la valeur d'un sous mot-clé (key)
321 return self.getMocle(key)
323 def getMocle(self, key):
325 Retourne la valeur du sous mot-clé key
326 Ce sous mot-clé peut exister, avoir une valeur par defaut ou etre
327 dans un BLOC fils de self
329 # on cherche dans les mots cles presents, le mot cle de nom key
330 # s'il est là on retourne sa valeur (méthode getVal)
331 for child in self.mcListe:
333 return child.getValeur()
334 # Si on n a pas trouve de mot cle present on retourne le defaut
335 # eventuel pour les mots cles accessibles dans la definition
338 d = self.definition.entites[key]
339 if d.label == 'SIMP':
341 elif d.label == 'FACT':
342 # il faut construire les objets necessaires pour
343 # evaluer les conditions des blocs eventuels (a faire)
346 if d.statut != 'c' and d.statut != 'd':
349 return d(val=None, nom=key, parent=self)
351 # le mot cle n est pas defini a ce niveau
353 # Si on a toujours rien trouve, on cherche dans les blocs presents
354 # On suppose que tous les blocs possibles ont ete crees meme ceux
355 # induits par un mot cle simple absent avec defaut (???)
356 for mc in self.mcListe:
360 return mc.getMocle(key)
362 # On n a rien trouve dans ce bloc, on passe au suivant
364 # On a rien trouve, le mot cle est absent.
365 # On leve une exception
366 raise IndexError("Le mot cle %s n existe pas dans %s" % (key, self))
368 def getChild(self, name, restreint='non'):
370 Retourne le fils de self de nom name ou None s'il n'existe pas
371 Si restreint vaut oui : ne regarde que dans la mcListe
372 Si restreint vaut non : regarde aussi dans les entites possibles
373 avec defaut (Ce dernier cas n'est utilisé que dans le catalogue)
375 for v in self.mcListe:
378 if restreint == 'non':
380 entite = self.definition.entites[name]
381 if entite.label == 'SIMP' or (entite.label == 'FACT' and entite.statut in ('c', 'd')):
382 return entite(None, name, None)
388 def append_mc_global(self, mc):
390 Ajoute le mot-clé mc à la liste des mots-clés globaux de l'étape
392 etape = self.getEtape()
395 etape.mc_globaux[nom] = mc
397 def append_mc_global_jdc(self, mc):
399 Ajoute le mot-clé mc à la liste des mots-clés globaux du jdc
402 self.jdc.mc_globaux[nom] = mc
405 """ Retourne une copie de self """
406 objet = self.makeobjet()
407 # FR : attention !!! avec makeobjet, objet a le meme parent que self
408 # ce qui n'est pas du tout bon dans le cas d'une copie !!!!!!!
409 # FR : peut-on passer par là autrement que dans le cas d'une copie ???
410 # FR --> je suppose que non
411 # XXX CCAR : le pb c'est qu'on vérifie ensuite quel parent avait l'objet
412 # Il me semble preferable de changer le parent a la fin quand la copie
414 objet.valeur = copy(self.valeur)
415 objet.val = copy(self.val)
417 for obj in self.mcListe:
419 new_obj.reparent(objet)
420 objet.mcListe.append(new_obj)
423 def reparent(self, parent):
425 Cette methode sert a reinitialiser la parente de l'objet
428 self.jdc = parent.getJdcRoot()
429 self.etape = parent.etape
430 for mocle in self.mcListe:
433 def getSd_utilisees(self):
435 Retourne la liste des concepts qui sont utilisés à l'intérieur de self
436 ( comme valorisation d'un MCS)
439 for child in self.mcListe:
440 l.extend(child.getSd_utilisees())
443 def getSd_mcs_utilisees(self):
445 Retourne la ou les SD utilisée par self sous forme d'un dictionnaire :
446 - Si aucune sd n'est utilisée, le dictionnaire est vide.
447 - Sinon, les clés du dictionnaire sont les mots-clés derrière lesquels on
448 trouve des sd ; la valeur est la liste des sd attenante.
451 { 'VALE_F': [ <Cata.cata.fonction_sdaster instance at 0x9419854>,
452 <Cata.cata.fonction_sdaster instance at 0x941a204> ],
453 'MODELE': [<Cata.cata.modele instance at 0x941550c>] }
456 for child in self.mcListe:
457 daux = child.getSd_mcs_utilisees()
459 dico[cle] = dico.get(cle, [])
460 dico[cle].extend(daux[cle])
463 def getMcsWithCo(self, co):
465 Cette methode retourne l'objet MCSIMP fils de self
466 qui a le concept co comme valeur.
467 En principe, elle ne doit etre utilisee que pour les concepts
468 instances de la classe CO
471 for child in self.mcListe:
472 l.extend(child.getMcsWithCo(co))
477 Cette methode retourne tous les concepts instances de CO
480 for child in self.mcListe:
481 l.extend(child.getAllCo())
485 def intersection_vide(dict1, dict2):
486 """Verification qu'il n'y a pas de clé commune entre 'dict1' et 'dict2'."""
489 inter = sk1.intersection(sk2)
492 print(('ERREUR: Mot(s)-clef(s) vu(s) plusieurs fois :', tuple(inter)))