2 # Copyright (C) 2007-2021 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 a verifier et a executer
27 from __future__ import absolute_import
28 from __future__ import print_function
30 from builtins import str
41 from . import N_MCCOMPO
42 from .N_Exception import AsException
44 from .N_utils import AsType
45 from .N_ASSD import ASSD
48 class ETAPE(N_MCCOMPO.MCCOMPO):
51 Cette classe herite de MCCOMPO car ETAPE est un OBJECT composite
56 # L'attribut de classe codex est utilise pour rattacher le module de calcul eventuel (voir Build)
57 # On le met a None pour indiquer qu'il n'y a pas de module de calcul
61 def __init__(self, oper=None, reuse=None, args={}, niveau=4):
64 - definition : objet portant les attributs de definition d'une etape de type operateur. Il
65 est initialise par l'argument oper.
66 - reuse : indique le concept d'entree reutilise. Il se trouvera donc en sortie
67 si les conditions d'execution de l'operateur l'autorise
68 - valeur : arguments d'entree de type mot-cle=valeur. Initialise avec l'argument args.
69 - objPyxbDeConstruction
71 # faut il le faire ds MC_Build ?
72 # traitement de Pyxb si Pyxb
73 self.dicoPyxbDeConstruction = args.get('dicoPyxbDeConstruction', None)
74 if self.dicoPyxbDeConstruction :
75 del args['dicoPyxbDeConstruction']
76 self.objPyxbDeConstruction=self.dicoPyxbDeConstruction['objEnPyxb']
78 self.objPyxbDeConstruction=None
79 self.definition = oper
83 self.parent = CONTEXT.getCurrentStep()
86 self.idracine = oper.label
87 self.appel = N_utils.calleeWhere(niveau)
89 self.doitEtreRecalculee = False
96 def makeRegister(self):
98 Initialise les attributs jdc, id, niveau et realise les
99 enregistrements necessaires
102 #print ('makeRegister de ETAPE')
104 self.jdc = self.parent.getJdcRoot()
105 self.id = self.parent.register(self)
108 self.jdc = self.parent = None
112 def nettoiargs(self):
114 Cette methode a pour fonction de retirer tous les arguments egaux a None
115 de la liste des arguments. Ils sont supposes non presents et donc retires.
117 for k in list(self.valeur.keys()):
118 if self.valeur[k] == None:
123 Demande la construction des sous-objets et les stocke dans l'attribut
126 self.mcListe = self.buildMc()
128 def buildSd(self, nom):
130 Construit le concept produit de l'operateur. Deux cas
131 peuvent se presenter :
133 - le parent n'est pas defini. Dans ce cas, l'etape prend en charge la creation
134 et le nommage du concept.
136 - le parent est defini. Dans ce cas, l'etape demande au parent la creation et
137 le nommage du concept.
143 sd = self.parent.createSdprod(self, nom)
144 if type(self.definition.op_init) == types.FunctionType:
145 self.definition.op_init(*(
146 self, self.parent.g_context))
148 sd = self.getSdProd()
149 # On n'utilise pas self.definition.op_init car self.parent
151 if sd != None and self.reuse == None:
152 # On ne nomme le concept que dans le cas de non reutilisation
155 except AsException as e:
156 raise AsException("Etape ", self.nom, 'ligne : ', self.appel[0],
157 'fichier : ', self.appel[1], e)
161 l = traceback.format_exception(
162 sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])
163 raise AsException("Etape ", self.nom, 'ligne : ', self.appel[0],
164 'fichier : ', self.appel[1] + '\n',
172 Cette methode est un point d'entree prevu pour realiser une execution immediatement
173 apres avoir construit les mots cles et le concept produit.
174 Par defaut, elle ne fait rien. Elle doit etre surchargee dans une autre partie du programme.
180 Retourne le concept resultat de l'etape
182 - cas 1 : sd_prod de oper n'est pas une fonction
183 il s'agit d'une sous classe de ASSD
184 on construit le sd a partir de cette classe
186 - cas 2 : il s'agit d'une fonction
187 on l'evalue avec les mots-cles de l'etape (mcListe)
188 on construit le sd a partir de la classe obtenue
191 if type(self.definition.sd_prod) == types.FunctionType:
192 d = self.creeDictValeurs(self.mcListe)
194 sd_prod = self.definition.sd_prod(*(), **d)
197 except Exception as exc:
199 traceback.print_exc()
200 raise AsException("impossible d affecter un type au resultat:",
203 sd_prod = self.definition.sd_prod
204 # on teste maintenant si la SD est reutilisee ou s'il faut la creer
205 if self.definition.reentrant != 'n' and self.reuse:
206 # Le concept produit est specifie reutilise (reuse=xxx). C'est une erreur mais non fatale.
207 # Elle sera traitee ulterieurement.
210 self.sd = sd_prod(etape=self)
211 # Si l'operateur est obligatoirement reentrant et reuse n'a pas ete specifie, c'est une erreur.
212 # On ne fait rien ici. L'erreur sera traiter par la suite.
214 if self.sd is not None and not isinstance(self.sd, ASSD):
215 raise AsException("""
216 Impossible de typer le resultat !
218 Utilisateur : Soit la valeur fournie derrière "reuse" est incorrecte,
219 soit il y a une "," a la fin d'une commande precedente.
220 Developpeur : La fonction "sd_prod" retourne un type invalide.""")
223 def getType_produit(self):
225 return self.getType_produit_brut()
229 def getType_produit_brut(self):
231 Retourne le type du concept resultat de l'etape
233 - cas 1 : sd_prod de oper n'est pas une fonction
234 il s'agit d'une sous classe de ASSD
235 on retourne le nom de la classe
236 - cas 2 : il s'agit d'une fonction
237 on l'evalue avec les mots-cles de l'etape (mcListe)
238 et on retourne son resultat
240 if type(self.definition.sd_prod) == types.FunctionType:
241 d = self.creeDictValeurs(self.mcListe)
242 sd_prod = self.definition.sd_prod(*(), **d)
244 sd_prod = self.definition.sd_prod
249 Retourne l'etape a laquelle appartient self
250 Un objet de la categorie etape doit retourner self pour indiquer que
251 l'etape a ete trouvee
257 Methode qui supprime toutes les references arrières afin que l'objet puisse
258 etre correctement detruit par le garbage collector
260 N_MCCOMPO.MCCOMPO.supprime(self)
263 for name in dir(self):
264 if name.startswith('_cache_'):
265 setattr(self, name, None)
272 def getCreated_sd(self):
273 """Retourne la liste des sd reellement produites par l'etape.
274 Si reuse est present, `self.sd` a ete creee avant, donc n'est pas dans
276 if not self.reuse and self.sd:
282 Indique si l'etape est active (1) ou inactive (0)
286 def setCurrentStep(self):
288 Methode utilisee pour que l etape self se declare etape
289 courante. Utilise par les macros
291 cs = CONTEXT.getCurrentStep()
292 if self.parent != cs:
293 raise AsException("L'etape courante", cs.nom, cs,
294 "devrait etre le parent de", self.nom, self)
296 CONTEXT.unsetCurrentStep()
297 CONTEXT.setCurrentStep(self)
299 def resetCurrentStep(self):
301 Methode utilisee par l'etape self qui remet son etape parent comme
304 cs = CONTEXT.getCurrentStep()
306 raise AsException("L'etape courante", cs.nom, cs,
307 "devrait etre", self.nom, self)
309 CONTEXT.unsetCurrentStep()
310 CONTEXT.setCurrentStep(self.parent)
312 def issubstep(self, etape):
314 Cette methode retourne un entier indiquant si etape est une
315 sous etape de self ou non
318 Une etape simple n'a pas de sous etape
322 def getFile(self, unite=None, fic_origine='', fname=None):
324 Retourne le nom du fichier correspondant a un numero d'unite
325 logique (entier) ainsi que le source contenu dans le fichier
328 return self.jdc.getFile(unite=unite, fic_origine=fic_origine, fname=fname)
331 if os.path.exists("fort." + str(unite)):
332 fname = "fort." + str(unite)
334 raise AsException("Impossible de trouver le fichier correspondant"
335 " a l unite %s" % unite)
336 if not os.path.exists(fname):
337 raise AsException("%s n'est pas un fichier existant" % unite)
338 fproc = open(fname, 'r')
341 text = text.replace('\r\n', '\n')
342 linecache.cache[fname] = 0, 0, text.split('\n'), fname
345 def accept(self, visitor):
347 Cette methode permet de parcourir l'arborescence des objets
348 en utilisant le pattern VISITEUR
350 visitor.visitETAPE(self)
352 def updateContext(self, d):
354 Cette methode doit updater le contexte fournit par
355 l'appelant en argument (d) en fonction de sa definition
357 if type(self.definition.op_init) == types.FunctionType:
358 self.definition.op_init(*(self, d))
360 d[self.sd.nom] = self.sd
363 """ Methode qui retourne une copie de self non enregistree auprès du JDC
368 etape.state = 'modified'
373 for objet in self.mcListe:
374 new_obj = objet.copy()
375 new_obj.reparent(etape)
376 etape.mcListe.append(new_obj)
379 def copyReuse(self, old_etape):
380 """ Methode qui copie le reuse d'une autre etape.
382 if hasattr(old_etape, "reuse"):
383 self.reuse = old_etape.reuse
385 def copySdnom(self, old_etape):
386 """ Methode qui copie le sdnom d'une autre etape.
388 if hasattr(old_etape, "sdnom"):
389 self.sdnom = old_etape.sdnom
391 def reparent(self, parent):
393 Cette methode sert a reinitialiser la parente de l'objet
396 self.jdc = parent.getJdcRoot()
398 for mocle in self.mcListe:
400 if self.sd and self.reuse == None:
401 self.sd.jdc = self.jdc
403 def getCmd(self, nomcmd):
405 Methode pour recuperer la definition d'une commande
406 donnee par son nom dans les catalogues declares
408 Appele par un ops d'une macro en Python
410 return self.jdc.getCmd(nomcmd)
412 def copyIntern(self, etape):
414 Methode permettant lors du processus de recopie de copier
415 les elements internes d'une etape dans une autre
419 def fullCopy(self, parent=None):
421 Methode permettant d'effectuer une copie complète
422 d'une etape (y compris concept produit, elements internes)
423 Si l'argument parent est fourni, la nouvelle etape
424 aura cet objet comme parent.
426 new_etape = self.copy()
427 new_etape.copyReuse(self)
428 new_etape.copySdnom(self)
430 new_etape.reparent(parent)
432 new_sd = self.sd.__class__(etape=new_etape)
433 new_etape.sd = new_sd
434 if self.reuse == None:
435 new_etape.parent.nommerSDProd(new_sd, self.sd.nom)
437 new_sd.setName(self.sd.nom)
438 new_etape.copyIntern(self)
441 def resetJdc(self, new_jdc):
443 Reinitialise le nommage du concept de l'etape lors d'un changement de jdc
445 if self.sd and self.reuse == None:
446 self.parent.nommerSDProd(self.sd, self.sd.nom)
449 """Permet savoir si on a affaire a la commande INCLUDE
450 car le comportement de ces macros est particulier.
452 return self.nom.startswith('INCLUDE')
454 def sdAccessible(self):
455 """Dit si on peut acceder aux "valeurs" (jeveux) de l'ASSD produite par l'etape.
458 print(('`- ETAPE sdAccessible :', self.nom))
459 return self.parent.sdAccessible()
461 def getConcept(self, nomsd):
463 Methode pour recuperer un concept a partir de son nom
465 # pourrait etre appelee par une commande fortran faisant appel a des fonctions python
466 # on passe la main au parent
467 return self.parent.getConcept(nomsd)