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 MACRO_ETAPE qui sert à vérifier et à exécuter
31 from warnings import warn
36 from N_Exception import AsException
38 from N_utils import AsType
40 from N_ASSD import ASSD
41 from N_info import message, SUPERV
44 class MACRO_ETAPE(N_ETAPE.ETAPE):
52 def __init__(self, oper=None, reuse=None, args={}):
55 - definition : objet portant les attributs de définition d'une étape
56 de type macro-commande. Il est initialisé par
58 - reuse : indique le concept d'entrée réutilisé. Il se trouvera donc
59 en sortie si les conditions d'exécution de l'opérateur
61 - valeur : arguments d'entrée de type mot-clé=valeur. Initialisé
64 N_ETAPE.ETAPE.__init__(self, oper, reuse, args, niveau=5)
67 self.current_context = {}
68 self.macro_const_context = {}
69 self.index_etape_courante = 0
71 self.index_etapes = {}
72 # Dans le cas d'une macro écrite en Python, l'attribut Outputs est un
73 # dictionnaire qui contient les concepts produits de sortie
74 # (nom : ASSD) déclarés dans la fonction sd_prod
77 self.UserError = "UserError"
78 # permet de stocker le nom du dernier concept nommé dans la macro
81 def make_register(self):
83 Initialise les attributs jdc, id, niveau et réalise les enregistrements
86 N_ETAPE.ETAPE.make_register(self)
88 self.UserError = self.jdc.UserError
90 self.UserError = "UserError"
92 def Build_sd(self, nom):
94 Construit le concept produit de l'opérateur. Deux cas
95 peuvent se présenter :
97 - le parent n'est pas défini. Dans ce cas, l'étape prend en charge
98 la création et le nommage du concept.
100 - le parent est défini. Dans ce cas, l'étape demande au parent la
101 création et le nommage du concept.
104 # message.debug(SUPERV, "%s", self.nom)
107 # On positionne la macro self en tant que current_step pour que les
108 # étapes créées lors de l'appel à sd_prod et à op_init aient la macro
110 self.set_current_step()
112 sd = self.parent.create_sdprod(self, nom)
113 if type(self.definition.op_init) == types.FunctionType:
114 apply(self.definition.op_init, (
115 self, self.parent.g_context))
117 sd = self.get_sd_prod()
118 if sd != None and self.reuse == None:
119 # On ne nomme le concept que dans le cas de non reutilisation
122 self.reset_current_step()
123 except AsException, e:
124 self.reset_current_step()
125 raise AsException("Etape ", self.nom, 'ligne : ', self.appel[0],
126 'fichier : ', self.appel[1], e)
127 except (EOFError, self.UserError):
128 # Le retablissement du step courant n'est pas strictement
129 # necessaire. On le fait pour des raisons de coherence
130 self.reset_current_step()
133 self.reset_current_step()
134 l = traceback.format_exception(
135 sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])
136 raise AsException("Etape ", self.nom, 'ligne : ', self.appel[0],
137 'fichier : ', self.appel[1] + '\n',
143 def get_sd_prod(self):
145 Retourne le concept résultat d'une macro étape
146 La difference avec une etape ou une proc-etape tient a ce que
147 le concept produit peut exister ou pas
149 Si sd_prod == None le concept produit n existe pas on retourne None
152 - cas 1 : sd_prod n'est pas une fonction
153 il s'agit d'une sous classe de ASSD
154 on construit le sd à partir de cette classe
156 - cas 2 : sd_prod est une fonction
157 on l'évalue avec les mots-clés de l'étape (mc_liste)
158 on construit le sd à partir de la classe obtenue
161 sd_prod = self.definition.sd_prod
164 if type(self.definition.sd_prod) == types.FunctionType:
165 d = self.cree_dict_valeurs(self.mc_liste)
167 # la sd_prod d'une macro a l'objet macro_etape lui meme en premier argument
168 # Comme sd_prod peut invoquer la méthode type_sdprod qui ajoute
169 # les concepts produits dans self.sdprods, il faut le mettre à
170 # zéro avant de l'appeler
172 sd_prod = apply(sd_prod, (self,), d)
173 except (EOFError, self.UserError):
175 except Exception, exc:
177 traceback.print_exc()
178 raise AsException("impossible d affecter un type au resultat:",
181 # on teste maintenant si la SD est réutilisée ou s'il faut la créer
182 if self.definition.reentrant != 'n' and self.reuse:
183 # Le concept produit est specifie reutilise (reuse=xxx). C'est une erreur mais non fatale.
184 # Elle sera traitee ulterieurement.
190 self.sd = sd_prod(etape=self)
191 self.typret = sd_prod
192 # Si la commande est obligatoirement reentrante et reuse n'a pas ete specifie, c'est une erreur.
193 # On ne fait rien ici. L'erreur sera traitee par la suite.
195 if self.sd is not None and not isinstance(self.sd, ASSD):
196 raise AsException("""
197 Impossible de typer le résultat !
199 Utilisateur : Soit la valeur fournie derrière "reuse" est incorrecte,
200 soit il y a une "," à la fin d'une commande précédente.
201 Développeur : La fonction "sd_prod" retourne un type invalide.""")
204 def get_type_produit(self, force=0):
206 return self.get_type_produit_brut(force)
208 # traceback.print_exc()
211 def get_type_produit_brut(self, force=0):
213 Retourne le type du concept résultat de l'étape et eventuellement type
214 les concepts produits "à droite" du signe égal (en entrée)
217 - cas 1 : sd_prod de oper n'est pas une fonction
218 il s'agit d'une sous classe de ASSD
219 on retourne le nom de la classe
220 - cas 2 : il s'agit d'une fonction
221 on l'évalue avec les mots-clés de l'étape (mc_liste)
222 et on retourne son résultat
224 if not force and hasattr(self, 'typret'):
227 if type(self.definition.sd_prod) == types.FunctionType:
228 d = self.cree_dict_valeurs(self.mc_liste)
229 # Comme sd_prod peut invoquer la méthode type_sdprod qui ajoute
230 # les concepts produits dans self.sdprods, il faut le mettre à zéro
232 sd_prod = apply(self.definition.sd_prod, (self,), d)
234 sd_prod = self.definition.sd_prod
237 def get_contexte_avant(self, etape):
239 Retourne le dictionnaire des concepts connus avant etape
240 pour les commandes internes a la macro
241 On tient compte des commandes qui modifient le contexte
242 comme DETRUIRE ou les macros
244 # L'étape courante pour laquelle le contexte a été calculé est
245 # mémorisée dans self.index_etape_courante
246 # message.debug(SUPERV, "g_context : %s", [k for k, v in self.g_context.items() if isinstance(v, ASSD)])
247 # message.debug(SUPERV, "current_context : %s", [k for k, v in
248 # self.current_context.items() if isinstance(v, ASSD)])
249 d = self.current_context = self.g_context.copy()
252 # retirer les sd produites par 'etape'
253 sd_names = [sd.nom for sd in etape.get_created_sd()]
254 # message.debug(SUPERV, "etape: %s, reuse : %s, sdprods de %s : %s",
255 # self.nom, etape.reuse, etape.nom, sd_names)
261 # Exemple avec INCLUDE_MATERIAU appelé dans une macro.
262 # Les fonctions restent uniquement dans le contexte de INCLUDE_MATERIAU,
263 # elles ne sont donc pas dans le contexte de la macro appelante.
264 # from warnings import warn
265 # warn("concept '%s' absent du contexte de %s" % (nom, self.nom),
266 # RuntimeWarning, stacklevel=2)
271 Méthode qui supprime toutes les références arrières afin que
272 l'objet puisse etre correctement détruit par le garbage collector
274 N_MCCOMPO.MCCOMPO.supprime(self)
279 for concept in self.sdprods:
281 for etape in self.etapes:
284 def clean(self, netapes):
285 """Nettoie les `netapes` dernières étapes de la liste des étapes."""
286 if self.jdc.hist_etape:
288 for i in xrange(netapes):
289 e = self.etapes.pop()
295 # message.debug(SUPERV, "MACRO.clean - etape = %s - refcount(e) = %d",
296 # e.nom, sys.getrefcount(e))
297 del self.index_etapes[e]
299 def type_sdprod(self, co, t):
301 Cette methode a pour fonction de typer le concept co avec le type t
302 dans les conditions suivantes :
303 1. co est un concept produit de self
304 2. co est un concept libre : on le type et on l attribue à self
306 Elle enregistre egalement les concepts produits (on fait l hypothese
307 que la liste sdprods a été correctement initialisee, vide probablement)
309 if not hasattr(co, 'etape'):
310 # Le concept vaut None probablement. On ignore l'appel
313 # On cherche a discriminer les differents cas de typage d'un concept
314 # produit par une macro qui est specifie dans un mot cle simple.
315 # On peut passer plusieurs fois par type_sdprod ce qui explique
316 # le nombre important de cas.
318 # Cas 1 : Le concept est libre. Il vient d'etre cree par CO(nom)
319 # Cas 2 : Le concept est produit par la macro. On est deja passe par type_sdprod.
320 # Cas semblable a Cas 1.
321 # Cas 3 : Le concept est produit par la macro englobante (parent). On transfere
322 # la propriete du concept de la macro parent a la macro courante (self)
323 # en verifiant que le type est valide
324 # Cas 4 : La concept est la propriete d'une etape fille. Ceci veut dire qu'on est
325 # deja passe par type_sdprod et que la propriete a ete transfere a une
326 # etape fille. Cas semblable a Cas 3.
327 # Cas 5 : Le concept est produit par une etape externe a la macro.
330 # Cas 1 : le concept est libre
331 # On l'attache a la macro et on change son type dans le type demande
332 # Recherche du mot cle simple associe au concept
333 mcs = self.get_mcs_with_co(co)
335 raise AsException("""Erreur interne.
336 Il ne devrait y avoir qu'un seul mot cle porteur du concept CO (%s)""" % co)
338 if not self.typeCO in mcs.definition.type:
339 raise AsException("""Erreur interne.
340 Impossible de changer le type du concept (%s). Le mot cle associe ne supporte pas CO mais seulement (%s)""" % (co, mcs.definition.type))
342 # affectation du bon type du concept
343 # message.debug(SUPERV, "MACRO.type_sdprod : changement de type de
346 self.sdprods.append(co)
348 elif co.etape == self:
349 # Cas 2 : le concept est produit par la macro (self)
350 # On est deja passe par type_sdprod (Cas 1 ou 3).
351 # XXX Peut-il être créer par une autre macro ?
352 # On vérifie juste que c'est un vrai CO non déjà typé
353 # if co.etape == co._etape:
354 if co.is_typco() == 1:
355 # Le concept a été créé par la macro (self)
356 # On peut changer son type
359 # Le concept a été créé par une macro parente
360 # Le type du concept doit etre coherent avec le type demande
362 if not isinstance(co, t):
363 raise AsException("""Erreur interne.
364 Le type demande (%s) et le type du concept (%s) devraient etre derives""" % (t, co.__class__))
366 self.sdprods.append(co)
368 elif co.etape == self.parent:
369 # Cas 3 : le concept est produit par la macro parente (self.parent)
370 # on transfere la propriete du concept a la macro fille
371 # et on change le type du concept comme demande
372 # Au prealable, on verifie que le concept existant (co) est une instance
373 # possible du type demande (t)
374 # Cette règle est normalement cohérente avec les règles de
375 # vérification des mots-clés
376 if not isinstance(co, t):
377 raise AsException("""
378 Impossible de changer le type du concept produit (%s) en (%s).
379 Le type actuel (%s) devrait etre une classe derivee du nouveau type (%s)""" % (co, t, co.__class__, t))
380 mcs = self.get_mcs_with_co(co)
382 raise AsException("""Erreur interne.
383 Il ne devrait y avoir qu'un seul mot cle porteur du concept CO (%s)""" % co)
385 if not self.typeCO in mcs.definition.type:
386 raise AsException("""Erreur interne.
387 Impossible de changer le type du concept (%s). Le mot cle associe ne supporte pas CO mais seulement (%s)""" % (co, mcs.definition.type))
389 # On ne change pas le type car il respecte la condition isinstance(co,t)
391 self.sdprods.append(co)
393 elif self.issubstep(co.etape):
394 # Cas 4 : Le concept est propriété d'une sous etape de la macro (self).
395 # On est deja passe par type_sdprod (Cas 3 ou 1).
396 # Il suffit de le mettre dans la liste des concepts produits (self.sdprods)
397 # Le type du concept et t doivent etre derives.
398 # Il n'y a aucune raison pour que la condition ne soit pas
400 if not isinstance(co, t):
401 raise AsException("""Erreur interne.
402 Le type demande (%s) et le type du concept (%s) devraient etre derives""" % (t, co.__class__))
403 self.sdprods.append(co)
406 # Cas 5 : le concept est produit par une autre étape
410 def issubstep(self, etape):
412 Cette methode retourne un entier indiquant si etape est une
413 sous etape de la macro self ou non
417 if etape in self.etapes:
419 for etap in self.etapes:
420 if etap.issubstep(etape):
424 def register(self, etape):
426 Enregistrement de etape dans le contexte de la macro : liste etapes
427 et demande d enregistrement global aupres du JDC
429 self.etapes.append(etape)
430 self.index_etapes[etape] = len(self.etapes) - 1
431 idetape = self.jdc.g_register(etape)
434 def reg_sd(self, sd):
436 Methode appelee dans l __init__ d un ASSD a sa creation pour
437 s enregistrer (reserve aux ASSD créés au sein d'une MACRO)
439 return self.jdc.o_register(sd)
441 def create_sdprod(self, etape, nomsd):
443 Cette methode doit fabriquer le concept produit retourne
444 par l'etape etape et le nommer.
446 Elle est appelée à l'initiative de l'etape
447 pendant le processus de construction de cette etape : methode __call__
448 de la classe CMD (OPER ou MACRO)
449 Ce travail est réalisé par le contexte supérieur (etape.parent)
450 car dans certains cas, le concept ne doit pas etre fabriqué mais
451 l'etape doit simplement utiliser un concept préexistant.
452 - Cas 1 : etape.reuse != None : le concept est réutilisé
453 - Cas 2 : l'étape appartient à une macro qui a déclaré un concept
454 de sortie qui doit etre produit par cette etape.
456 if self.Outputs.has_key(nomsd):
457 # Il s'agit d'un concept de sortie de la macro. Il ne faut pas le créer
458 # Il faut quand meme appeler la fonction sd_prod si elle existe.
459 # get_type_produit le fait et donne le type attendu par la commande
460 # pour verification ultérieure.
461 sdprod = etape.get_type_produit_brut()
462 sd = self.Outputs[nomsd]
463 # On verifie que le type du concept existant sd.__class__ est un sur type de celui attendu
464 # Cette règle est normalement cohérente avec les règles de
465 # vérification des mots-clés
466 if not issubclass(sdprod, sd.__class__):
468 "Le type du concept produit %s devrait etre une sur classe de %s" % (sd.__class__, sdprod))
469 # La propriete du concept est transferee a l'etape avec le type
470 # attendu par l'étape
473 if self.reuse == sd and etape.reuse != sd \
474 and getattr(sd, "executed", 0) == 1: # n'a pas été pas détruit
475 raise AsException("Le concept '%s' est réentrant dans la macro-commande %s. "
476 "Il devrait donc l'être dans %s (produit sous le nom '%s')."
477 % (sd.nom, self.nom, etape.nom, nomsd))
478 # On donne au concept le type produit par la sous commande.
479 # Le principe est le suivant : apres avoir verifie que le type deduit par la sous commande
480 # est bien coherent avec celui initialement affecte par la macro (voir ci dessus)
481 # on affecte au concept ce type car il peut etre plus precis
482 # (derive, en general)
483 sd.__class__ = sdprod
484 # On force également le nom stocké dans l'attribut sdnom : on lui donne le nom
485 # du concept associé à nomsd
487 # pour l'ajouter au contexte de la macro
488 self.g_context[sd.nom] = sd
489 elif etape.definition.reentrant != 'n' and etape.reuse != None:
490 # On est dans le cas d'une commande avec reutilisation d'un concept existant
491 # get_sd_prod fait le necessaire : verifications, associations, etc. mais ne cree
492 # pas un nouveau concept. Il retourne le concept reutilise
493 sd = etape.get_sd_prod()
494 # Dans le cas d'un concept nomme automatiquement : _xxx, __xxx,
495 # On force le nom stocke dans l'attribut sdnom de l'objet etape : on lui donne le nom
496 # du concept reutilise (sd ou etape.reuse c'est pareil)
497 # Ceci est indispensable pour eviter des erreurs lors des verifications des macros
498 # En effet une commande avec reutilisation d'un concept verifie que le nom de
499 # la variable a gauche du signe = est le meme que celui du concept reutilise.
500 # Lorsqu'une telle commande apparait dans une macro, on supprime
501 # cette verification.
502 if (etape.sdnom == '' or etape.sdnom[0] == '_'):
505 # On est dans le cas de la creation d'un nouveau concept
506 sd = etape.get_sd_prod()
508 self.NommerSdprod(sd, nomsd)
511 def NommerSdprod(self, sd, sdnom, restrict='non'):
513 Cette méthode est appelée par les etapes internes de la macro.
514 La macro appelle le JDC pour valider le nommage.
515 On considère que l'espace de nom est unique et géré par le JDC.
516 Si le nom est déjà utilisé, l'appel lève une exception.
517 Si restrict=='non', on insère le concept dans le contexte du parent de la macro.
518 Si restrict=='oui', on insère le concept uniquement dans le contexte de la macro.
520 # Normalement, lorsqu'on appelle cette methode, on ne veut nommer que des concepts nouvellement crees.
521 # Le filtrage sur les concepts a creer ou a ne pas creer est fait dans la methode
522 # create_sdprod. La seule chose a verifier apres conversion eventuelle du nom
523 # est de verifier que le nom n'est pas deja attribue. Ceci est fait en delegant
524 # au JDC par l'intermediaire du parent.
525 # message.debug(SUPERV, "macro results = %s, (sdnom: %r, restrict: %r)",
526 # self.Outputs.keys(), sdnom, restrict)
527 if self.Outputs.has_key(sdnom):
528 # Il s'agit d'un concept de sortie de la macro produit par une
530 sdnom = self.Outputs[sdnom].nom
532 if sdnom[0] in ('_', '.') and sdnom[1:].isdigit():
533 # il est déjà de la forme _9000012 ou .9000017
535 elif sdnom[0] == '_':
536 # Si le nom du concept commence par le caractère '_', on lui attribue
537 # un identificateur JEVEUX construit par gcncon.
538 # nom commençant par __ : il s'agit de concepts qui seront détruits
539 # nom commençant par _ : il s'agit de concepts intermediaires
541 if len(sdnom) > 1 and sdnom[1] == '_':
542 sdnom = self.gcncon('.')
544 sdnom = self.gcncon('_')
545 elif self.nom in ('INCLUDE', 'MACR_RECAL'):
546 # dans le cas d'INCLUDE, on passe
547 # MACR_RECAL fonctionne comme INCLUDE
550 # On est dans le cas d'un nom de concept global
551 # XXX à voir, création de CO() dans CALC_ESSAI (sdls139a)
552 if not sd.is_typco():
554 "Résultat non déclaré par la macro %s : %s" % (self.nom, sdnom))
556 if restrict == 'non':
557 # On demande le nommage au parent mais sans ajout du concept dans le contexte du parent
558 # car on va l'ajouter dans le contexte de la macro
559 self.parent.NommerSdprod(sd, sdnom, restrict='oui')
560 # On ajoute dans le contexte de la macro les concepts nommes
561 # Ceci est indispensable pour les CO (macro) dans un INCLUDE
562 self.g_context[sdnom] = sd
563 # message.debug(SUPERV, "g_context[%s] = %s", sdnom, sd)
565 # La demande de nommage vient probablement d'une macro qui a mis
566 # le concept dans son contexte. On ne traite plus que le nommage (restrict="oui")
567 # message.debug(SUPERV, "restrict=oui co[%s] = %s", sdnom, sd)
568 self.parent.NommerSdprod(sd, sdnom, restrict='oui')
570 def delete_concept_after_etape(self, etape, sd):
572 Met à jour les étapes de la MACRO qui sont après etape suite à
573 la disparition du concept sd
575 # Cette methode est définie dans le noyau mais ne sert que pendant la phase de creation
576 # des etapes et des concepts. Il n'y a aucun traitement particulier à réaliser
577 # Dans d'autres conditions, il faudrait surcharger cette méthode.
580 def get_created_sd(self):
581 """Retourne la liste des sd réellement produites par l'étape.
582 Si reuse est présent, `self.sd` a été créée avant, donc n'est pas dans
584 sdprods = self.sdprods[:]
585 if not self.reuse and self.sd:
586 sdprods.append(self.sd)
589 def get_last_concept(self):
590 """Retourne le dernier concept produit dans la macro.
591 Peut-être utile pour accéder au contenu 'fortran' dans une
593 return self.g_context.get(self.last, None)
595 def accept(self, visitor):
597 Cette methode permet de parcourir l'arborescence des objets
598 en utilisant le pattern VISITEUR
600 visitor.visitMACRO_ETAPE(self)
602 def update_context(self, d):
604 Met à jour le contexte contenu dans le dictionnaire d
605 Une MACRO_ETAPE peut ajouter plusieurs concepts dans le contexte
606 Une fonction enregistree dans op_init peut egalement modifier le contexte
608 if type(self.definition.op_init) == types.FunctionType:
609 apply(self.definition.op_init, (self, d))
611 d[self.sd.nom] = self.sd
612 for co in self.sdprods:
615 def make_include(self, unite=None, fname=None):
616 """Inclut un fichier dont l'unite logique est `unite` ou de nom `fname`"""
617 if unite is not None:
618 warn("'unite' is deprecated, please use 'fname' instead",
619 DeprecationWarning, stacklevel=2)
620 fname = 'fort.%s' % unite
623 f, text = self.get_file(fic_origine=self.parent.nom, fname=fname)
624 self.fichier_init = f
627 self.make_contexte(f, text)
629 def make_poursuite(self):
630 """Inclut un fichier poursuite"""
631 raise NotImplementedError('this method must be derivated (in Eficas)')
633 def make_contexte(self, f, text):
635 Interprete le texte fourni (text) issu du fichier f
636 dans le contexte du parent.
637 Cette methode est utile pour le fonctionnement des
640 # on execute le texte fourni dans le contexte forme par
641 # le contexte de l etape pere (global au sens Python)
642 # et le contexte de l etape (local au sens Python)
643 code = compile(text, f, 'exec')
644 d = self.g_context = self.macro_const_context
645 globs = self.get_global_contexte()
647 exec code in globs, d
648 # pour ne pas conserver des références sur tout
649 self.macro_const_context = {}
651 def get_global_contexte(self):
653 Cette methode retourne le contexte global fourni
654 par le parent(self) a une etape fille (l'appelant) pour
655 realiser des evaluations de texte Python (INCLUDE,...)
657 # Le contexte global est forme par concatenation du contexte
658 # du parent de self et de celui de l'etape elle meme (self)
659 # Pour les concepts, cela ne doit rien changer. Mais pour les constantes,
660 # les valeurs de get_contexte_avant sont moins récentes que dans
661 # get_global_contexte. On prend donc la précaution de ne pas écraser
663 d = self.parent.get_global_contexte()
664 d.update(self.g_context)
665 d.update([(k, v) for k, v in self.parent.get_contexte_avant(self).items()
666 if d.get(k) is None])
669 def get_contexte_courant(self, etape_fille_du_jdc=None):
671 Retourne le contexte tel qu'il est au moment de l'exécution de
675 # update car par ricochet on modifierait jdc.current_context
676 ctx.update(self.parent.get_contexte_courant(self))
677 # on peut mettre None car toujours en PAR_LOT='NON', donc la dernière
678 ctx.update(self.get_contexte_avant(None))
681 def get_concept(self, nomsd):
683 Méthode pour recuperer un concept à partir de son nom
684 dans le contexte du jdc connu avant l'exécution de la macro courante.
686 # chercher dans self.get_contexte_avant, puis si non trouve
687 # self.parent.get_concept est peut-etre plus performant
688 co = self.get_contexte_courant().get(nomsd.strip(), None)
689 if not isinstance(co, ASSD):
693 def get_concept_by_type(self, nomsd, typesd, etape=None):
695 Méthode pour récuperer un concept à partir de son nom et de son type.
696 Il aura comme père 'etape' (ou la macro courante si etape est absente).
698 return self.parent.get_concept_by_type(nomsd, typesd, etape=etape or self)
701 """ Méthode qui retourne une copie de self non enregistrée auprès du JDC
703 On surcharge la methode de ETAPE pour exprimer que les concepts crees
704 par la MACRO d'origine ne sont pas crees par la copie mais eventuellement
707 etape = N_ETAPE.ETAPE.copy(self)
711 def copy_intern(self, etape):
712 """ Cette méthode effectue la recopie des etapes internes d'une macro
713 passée en argument (etape)
716 self.index_etapes = {}
717 for etp in etape.etapes:
719 new_etp.copy_reuse(etp)
720 new_etp.copy_sdnom(etp)
721 new_etp.reparent(self)
723 new_sd = etp.sd.__class__(etape=new_etp)
726 new_sd.set_name(etp.sd.nom)
728 self.NommerSdprod(new_sd, etp.sd.nom)
729 new_etp.copy_intern(etp)
730 self.etapes.append(new_etp)
731 self.index_etapes[new_etp] = len(self.etapes) - 1
733 def reset_jdc(self, new_jdc):
735 Reinitialise l'etape avec un nouveau jdc parent new_jdc
737 if self.sd and self.reuse == None:
738 self.parent.NommerSdprod(self.sd, self.sd.nom)
739 for concept in self.sdprods:
740 self.parent.NommerSdprod(concept, concept.nom)
742 def reparent(self, parent):
744 Cette methode sert a reinitialiser la parente de l'objet
746 N_ETAPE.ETAPE.reparent(self, parent)
747 # on ne change pas la parenté des concepts. On s'assure uniquement que
748 # le jdc en référence est le bon
749 for concept in self.sdprods:
750 concept.jdc = self.jdc
751 for e in self.etapes:
754 def update_const_context(self, d):
756 Met à jour le contexte des constantes pour l'évaluation de
757 formules dans la macro.
759 # Dans le jdc, const_context est mis à jour par exec_compile
760 # Dans la macro, on n'a pas le code à compiler pour récupèrer les
761 # constantes locales à la macro. On demande donc explicitement de
762 # définir les constantes "locales".
763 self.macro_const_context.update(d)
765 def sd_accessible(self):
766 """On peut acceder aux "valeurs" (jeveux) des ASSD dans
767 les macro-commandes qui sont localement en PAR_LOT="NON"
771 print ' `- MACRO sd_accessible :', self.nom
772 return self.parent.sd_accessible() or not self.is_include()