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 ETAPE qui sert à vérifier et à exécuter
37 from N_Exception import AsException
39 from N_utils import AsType
40 from N_ASSD import ASSD
41 from N_info import message, SUPERV
44 class ETAPE(N_MCCOMPO.MCCOMPO):
47 Cette classe hérite de MCCOMPO car ETAPE est un OBJECT composite
52 # L'attribut de classe codex est utilisé pour rattacher le module de calcul éventuel (voir Build)
53 # On le met à None pour indiquer qu'il n'y a pas de module de calcul
57 def __init__(self, oper=None, reuse=None, args={}, niveau=4):
60 - definition : objet portant les attributs de définition d'une étape de type opérateur. Il
61 est initialisé par l'argument oper.
62 - reuse : indique le concept d'entrée réutilisé. Il se trouvera donc en sortie
63 si les conditions d'exécution de l'opérateur l'autorise
64 - valeur : arguments d'entrée de type mot-clé=valeur. Initialisé avec l'argument args.
66 self.definition = oper
70 self.parent = CONTEXT.get_current_step()
73 self.idracine = oper.label
74 self.appel = N_utils.callee_where(niveau)
81 def make_register(self):
83 Initialise les attributs jdc, id, niveau et réalise les
84 enregistrements nécessaires
87 self.jdc = self.parent.get_jdc_root()
88 self.id = self.parent.register(self)
91 self.jdc = self.parent = None
97 Cette methode a pour fonction de retirer tous les arguments egaux à None
98 de la liste des arguments. Ils sont supposés non présents et donc retirés.
100 for k in self.valeur.keys():
101 if self.valeur[k] == None:
106 Demande la construction des sous-objets et les stocke dans l'attribut
109 self.mc_liste = self.build_mc()
111 def Build_sd(self, nom):
113 Construit le concept produit de l'opérateur. Deux cas
114 peuvent se présenter :
116 - le parent n'est pas défini. Dans ce cas, l'étape prend en charge la création
117 et le nommage du concept.
119 - le parent est défini. Dans ce cas, l'étape demande au parent la création et
120 le nommage du concept.
123 # message.debug(SUPERV, "Build_sd %s", self.nom)
127 sd = self.parent.create_sdprod(self, nom)
128 if type(self.definition.op_init) == types.FunctionType:
129 apply(self.definition.op_init, (
130 self, self.parent.g_context))
132 sd = self.get_sd_prod()
133 # On n'utilise pas self.definition.op_init car self.parent
135 if sd != None and self.reuse == None:
136 # On ne nomme le concept que dans le cas de non reutilisation
139 except AsException, e:
140 raise AsException("Etape ", self.nom, 'ligne : ', self.appel[0],
141 'fichier : ', self.appel[1], e)
145 l = traceback.format_exception(
146 sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])
147 raise AsException("Etape ", self.nom, 'ligne : ', self.appel[0],
148 'fichier : ', self.appel[1] + '\n',
156 Cette methode est un point d'entree prevu pour realiser une execution immediatement
157 apres avoir construit les mots cles et le concept produit.
158 Par defaut, elle ne fait rien. Elle doit etre surchargee dans une autre partie du programme.
162 def get_sd_prod(self):
164 Retourne le concept résultat de l'étape
166 - cas 1 : sd_prod de oper n'est pas une fonction
167 il s'agit d'une sous classe de ASSD
168 on construit le sd à partir de cette classe
170 - cas 2 : il s'agit d'une fonction
171 on l'évalue avec les mots-clés de l'étape (mc_liste)
172 on construit le sd à partir de la classe obtenue
175 if type(self.definition.sd_prod) == types.FunctionType:
176 d = self.cree_dict_valeurs(self.mc_liste)
178 sd_prod = apply(self.definition.sd_prod, (), d)
181 except Exception, exc:
183 traceback.print_exc()
184 raise AsException("impossible d affecter un type au resultat:",
187 sd_prod = self.definition.sd_prod
188 # on teste maintenant si la SD est réutilisée ou s'il faut la créer
189 if self.definition.reentrant != 'n' and self.reuse:
190 # Le concept produit est specifie reutilise (reuse=xxx). C'est une erreur mais non fatale.
191 # Elle sera traitee ulterieurement.
194 self.sd = sd_prod(etape=self)
195 # Si l'operateur est obligatoirement reentrant et reuse n'a pas ete specifie, c'est une erreur.
196 # On ne fait rien ici. L'erreur sera traiter par la suite.
198 if self.sd is not None and not isinstance(self.sd, ASSD):
199 raise AsException("""
200 Impossible de typer le résultat !
202 Utilisateur : Soit la valeur fournie derrière "reuse" est incorrecte,
203 soit il y a une "," à la fin d'une commande précédente.
204 Développeur : La fonction "sd_prod" retourne un type invalide.""")
207 def get_type_produit(self):
209 return self.get_type_produit_brut()
213 def get_type_produit_brut(self):
215 Retourne le type du concept résultat de l'étape
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 type(self.definition.sd_prod) == types.FunctionType:
225 d = self.cree_dict_valeurs(self.mc_liste)
226 sd_prod = apply(self.definition.sd_prod, (), d)
228 sd_prod = self.definition.sd_prod
233 Retourne l'étape à laquelle appartient self
234 Un objet de la catégorie etape doit retourner self pour indiquer que
235 l'étape a été trouvée
241 Méthode qui supprime toutes les références arrières afin que l'objet puisse
242 etre correctement détruit par le garbage collector
244 N_MCCOMPO.MCCOMPO.supprime(self)
247 for name in dir(self):
248 if name.startswith('_cache_'):
249 setattr(self, name, None)
254 # message.debug(SUPERV, "__del__ ETAPE %s <%s>", getattr(self, 'nom', 'unknown'), self)
256 # message.debug(SUPERV, " sd : %s", self.sd.nom)
259 def get_created_sd(self):
260 """Retourne la liste des sd réellement produites par l'étape.
261 Si reuse est présent, `self.sd` a été créée avant, donc n'est pas dans
263 if not self.reuse and self.sd:
269 Indique si l'étape est active (1) ou inactive (0)
273 def set_current_step(self):
275 Methode utilisee pour que l etape self se declare etape
276 courante. Utilise par les macros
278 # message.debug(SUPERV, "call etape.set_current_step", stack_id=-1)
279 cs = CONTEXT.get_current_step()
280 if self.parent != cs:
281 raise AsException("L'étape courante", cs.nom, cs,
282 "devrait etre le parent de", self.nom, self)
284 CONTEXT.unset_current_step()
285 CONTEXT.set_current_step(self)
287 def reset_current_step(self):
289 Methode utilisee par l'etape self qui remet son etape parent comme
292 cs = CONTEXT.get_current_step()
294 raise AsException("L'étape courante", cs.nom, cs,
295 "devrait etre", self.nom, self)
297 CONTEXT.unset_current_step()
298 CONTEXT.set_current_step(self.parent)
300 def issubstep(self, etape):
302 Cette methode retourne un entier indiquant si etape est une
303 sous etape de self ou non
306 Une étape simple n'a pas de sous etape
310 def get_file(self, unite=None, fic_origine='', fname=None):
312 Retourne le nom du fichier correspondant à un numero d'unité
313 logique (entier) ainsi que le source contenu dans le fichier
316 return self.jdc.get_file(unite=unite, fic_origine=fic_origine, fname=fname)
319 if os.path.exists("fort." + str(unite)):
320 fname = "fort." + str(unite)
322 raise AsException("Impossible de trouver le fichier correspondant"
323 " a l unite %s" % unite)
324 if not os.path.exists(fname):
325 raise AsException("%s n'est pas un fichier existant" % unite)
326 fproc = open(fname, 'r')
329 text = text.replace('\r\n', '\n')
330 linecache.cache[fname] = 0, 0, text.split('\n'), fname
333 def accept(self, visitor):
335 Cette methode permet de parcourir l'arborescence des objets
336 en utilisant le pattern VISITEUR
338 visitor.visitETAPE(self)
340 def update_context(self, d):
342 Cette methode doit updater le contexte fournit par
343 l'appelant en argument (d) en fonction de sa definition
345 if type(self.definition.op_init) == types.FunctionType:
346 apply(self.definition.op_init, (self, d))
348 d[self.sd.nom] = self.sd
351 """ Méthode qui retourne une copie de self non enregistrée auprès du JDC
356 etape.state = 'modified'
361 for objet in self.mc_liste:
362 new_obj = objet.copy()
363 new_obj.reparent(etape)
364 etape.mc_liste.append(new_obj)
367 def copy_reuse(self, old_etape):
368 """ Méthode qui copie le reuse d'une autre étape.
370 if hasattr(old_etape, "reuse"):
371 self.reuse = old_etape.reuse
373 def copy_sdnom(self, old_etape):
374 """ Méthode qui copie le sdnom d'une autre étape.
376 if hasattr(old_etape, "sdnom"):
377 self.sdnom = old_etape.sdnom
379 def reparent(self, parent):
381 Cette methode sert a reinitialiser la parente de l'objet
384 self.jdc = parent.get_jdc_root()
386 for mocle in self.mc_liste:
388 if self.sd and self.reuse == None:
389 self.sd.jdc = self.jdc
391 def get_cmd(self, nomcmd):
393 Méthode pour recuperer la definition d'une commande
394 donnee par son nom dans les catalogues declares
396 Appele par un ops d'une macro en Python
398 return self.jdc.get_cmd(nomcmd)
400 def copy_intern(self, etape):
402 Méthode permettant lors du processus de recopie de copier
403 les elements internes d'une etape dans une autre
407 def full_copy(self, parent=None):
409 Méthode permettant d'effectuer une copie complète
410 d'une étape (y compris concept produit, éléments internes)
411 Si l'argument parent est fourni, la nouvelle étape
412 aura cet objet comme parent.
414 new_etape = self.copy()
415 new_etape.copy_reuse(self)
416 new_etape.copy_sdnom(self)
418 new_etape.reparent(parent)
420 new_sd = self.sd.__class__(etape=new_etape)
421 new_etape.sd = new_sd
422 if self.reuse == None:
423 new_etape.parent.NommerSdprod(new_sd, self.sd.nom)
425 new_sd.set_name(self.sd.nom)
426 new_etape.copy_intern(self)
429 def reset_jdc(self, new_jdc):
431 Reinitialise le nommage du concept de l'etape lors d'un changement de jdc
433 if self.sd and self.reuse == None:
434 self.parent.NommerSdprod(self.sd, self.sd.nom)
436 def is_include(self):
437 """Permet savoir si on a affaire à la commande INCLUDE
438 car le comportement de ces macros est particulier.
440 return self.nom.startswith('INCLUDE')
442 def sd_accessible(self):
443 """Dit si on peut acceder aux "valeurs" (jeveux) de l'ASSD produite par l'étape.
446 print '`- ETAPE sd_accessible :', self.nom
447 return self.parent.sd_accessible()
449 def get_concept(self, nomsd):
451 Méthode pour recuperer un concept à partir de son nom
453 # pourrait être appelée par une commande fortran faisant appel à des fonctions python
454 # on passe la main au parent
455 return self.parent.get_concept(nomsd)