]> SALOME platform Git repositories - tools/eficas.git/blob - Noyau/N_ETAPE.py
Salome HOME
Merge V9 dans Master
[tools/eficas.git] / Noyau / N_ETAPE.py
1 # coding=utf-8
2 # Copyright (C) 2007-2017   EDF R&D
3 #
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.
8 #
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.
13 #
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
17 #
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19
20
21 """
22     Ce module contient la classe ETAPE qui sert a verifier et a executer
23     une commande
24 """
25
26 # Modules Python
27 from __future__ import absolute_import
28 from __future__ import print_function
29 try :
30    from builtins import str
31 except :
32    pass
33 import types
34 import sys
35 import os
36 import linecache
37 import traceback
38 from copy import copy
39
40 # Modules EFICAS
41 from . import N_MCCOMPO
42 from .N_Exception import AsException
43 from . import N_utils
44 from .N_utils import AsType
45 from .N_ASSD import ASSD
46
47
48 class ETAPE(N_MCCOMPO.MCCOMPO):
49
50     """
51        Cette classe herite de MCCOMPO car ETAPE est un OBJECT composite
52
53     """
54     nature = "OPERATEUR"
55
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
58     # rattache
59     codex = None
60
61     def __init__(self, oper=None, reuse=None, args={}, niveau=4):
62         """
63         Attributs :
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
70         """
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']
77         else : 
78             self.objPyxbDeConstruction=None
79         self.definition = oper
80         self.reuse = reuse
81         self.valeur = args
82         self.nettoiargs()
83         self.parent = CONTEXT.getCurrentStep()
84         self.etape = self
85         self.nom = oper.nom
86         self.idracine = oper.label
87         self.appel = N_utils.calleeWhere(niveau)
88         self.mc_globaux = {}
89         self.sd = None
90         self.actif = 1
91         self.makeRegister()
92         self.icmd = None
93         print ('uuuuuuuuuuuuuuu fin init de ETAPE', self,oper)
94
95     def makeRegister(self):
96         """
97         Initialise les attributs jdc, id, niveau et realise les
98         enregistrements necessaires
99         surcharge dans Ihm
100         """
101         print ('makeRegister de  ETAPE')
102         if self.parent:
103             self.jdc = self.parent.getJdcRoot()
104             self.id = self.parent.register(self)
105             self.niveau = None
106         else:
107             self.jdc = self.parent = None
108             self.id = None
109             self.niveau = None
110
111     def nettoiargs(self):
112         """
113            Cette methode a pour fonction de retirer tous les arguments egaux a None
114            de la liste des arguments. Ils sont supposes non presents et donc retires.
115         """
116         for k in list(self.valeur.keys()):
117             if self.valeur[k] == None:
118                 del self.valeur[k]
119
120     def MCBuild(self):
121         """
122            Demande la construction des sous-objets et les stocke dans l'attribut
123            mcListe.
124         """
125         self.mcListe = self.buildMc()
126
127     def buildSd(self, nom):
128         """
129            Construit le concept produit de l'operateur. Deux cas
130            peuvent se presenter :
131
132              - le parent n'est pas defini. Dans ce cas, l'etape prend en charge la creation
133                et le nommage du concept.
134
135              - le parent est defini. Dans ce cas, l'etape demande au parent la creation et
136                le nommage du concept.
137
138         """
139         self.sdnom = nom
140         try:
141             if self.parent:
142                 sd = self.parent.createSdprod(self, nom)
143                 if type(self.definition.op_init) == types.FunctionType:
144                     self.definition.op_init(*(
145                         self, self.parent.g_context))
146             else:
147                 sd = self.getSdProd()
148                 # On n'utilise pas self.definition.op_init car self.parent
149                 # n'existe pas
150                 if sd != None and self.reuse == None:
151                     # On ne nomme le concept que dans le cas de non reutilisation
152                     # d un concept
153                     sd.setName(nom)
154         except AsException as e:
155             raise AsException("Etape ", self.nom, 'ligne : ', self.appel[0],
156                               'fichier : ', self.appel[1], e)
157         except EOFError:
158             raise
159         except:
160             l = traceback.format_exception(
161                 sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])
162             raise AsException("Etape ", self.nom, 'ligne : ', self.appel[0],
163                               'fichier : ', self.appel[1] + '\n',
164                               ''.join(l))
165
166         self.Execute()
167         return sd
168
169     def Execute(self):
170         """
171            Cette methode est un point d'entree prevu pour realiser une execution immediatement
172            apres avoir construit les mots cles et le concept produit.
173            Par defaut, elle ne fait rien. Elle doit etre surchargee dans une autre partie du programme.
174         """
175         return
176
177     def getSdProd(self):
178         """
179             Retourne le concept resultat de l'etape
180             Deux cas :
181                      - cas 1 : sd_prod de oper n'est pas une fonction
182                        il s'agit d'une sous classe de ASSD
183                        on construit le sd a partir de cette classe
184                        et on le retourne
185                      - cas 2 : il s'agit d'une fonction
186                        on l'evalue avec les mots-cles de l'etape (mcListe)
187                        on construit le sd a partir de la classe obtenue
188                        et on le retourne
189         """
190         if type(self.definition.sd_prod) == types.FunctionType:
191             d = self.creeDictValeurs(self.mcListe)
192             try:
193                 sd_prod = self.definition.sd_prod(*(), **d)
194             except EOFError:
195                 raise
196             except Exception as exc:
197                 if CONTEXT.debug:
198                     traceback.print_exc()
199                 raise AsException("impossible d affecter un type au resultat:",
200                                   str(exc))
201         else:
202             sd_prod = self.definition.sd_prod
203         # on teste maintenant si la SD est reutilisee ou s'il faut la creer
204         if self.definition.reentrant != 'n' and self.reuse:
205             # Le concept produit est specifie reutilise (reuse=xxx). C'est une erreur mais non fatale.
206             # Elle sera traitee ulterieurement.
207             self.sd = self.reuse
208         else:
209             self.sd = sd_prod(etape=self)
210             # Si l'operateur est obligatoirement reentrant et reuse n'a pas ete specifie, c'est une erreur.
211             # On ne fait rien ici. L'erreur sera traiter par la suite.
212         # precaution
213         if self.sd is not None and not isinstance(self.sd, ASSD):
214             raise AsException("""
215 Impossible de typer le resultat !
216 Causes possibles :
217    Utilisateur : Soit la valeur fournie derrière "reuse" est incorrecte,
218                  soit il y a une "," a la fin d'une commande precedente.
219    Developpeur : La fonction "sd_prod" retourne un type invalide.""")
220         return self.sd
221
222     def getType_produit(self):
223         try:
224             return self.getType_produit_brut()
225         except:
226             return None
227
228     def getType_produit_brut(self):
229         """
230             Retourne le type du concept resultat de l'etape
231             Deux cas :
232               - cas 1 : sd_prod de oper n'est pas une fonction
233                 il s'agit d'une sous classe de ASSD
234                 on retourne le nom de la classe
235               - cas 2 : il s'agit d'une fonction
236                 on l'evalue avec les mots-cles de l'etape (mcListe)
237                 et on retourne son resultat
238         """
239         if type(self.definition.sd_prod) == types.FunctionType:
240             d = self.creeDictValeurs(self.mcListe)
241             sd_prod = self.definition.sd_prod(*(), **d)
242         else:
243             sd_prod = self.definition.sd_prod
244         return sd_prod
245
246     def getEtape(self):
247         """
248            Retourne l'etape a laquelle appartient self
249            Un objet de la categorie etape doit retourner self pour indiquer que
250            l'etape a ete trouvee
251         """
252         return self
253
254     def supprime(self):
255         """
256            Methode qui supprime toutes les references arrières afin que l'objet puisse
257            etre correctement detruit par le garbage collector
258         """
259         N_MCCOMPO.MCCOMPO.supprime(self)
260         self.jdc = None
261         self.appel = None
262         for name in dir(self):
263             if name.startswith('_cache_'):
264                 setattr(self, name, None)
265         if self.sd:
266             self.sd.supprime()
267
268     def __del__(self):
269         pass
270
271     def getCreated_sd(self):
272         """Retourne la liste des sd reellement produites par l'etape.
273         Si reuse est present, `self.sd` a ete creee avant, donc n'est pas dans
274         cette liste."""
275         if not self.reuse and self.sd:
276             return [self.sd, ]
277         return []
278
279     def isActif(self):
280         """
281            Indique si l'etape est active (1) ou inactive (0)
282         """
283         return self.actif
284
285     def setCurrentStep(self):
286         """
287             Methode utilisee pour que l etape self se declare etape
288             courante. Utilise par les macros
289         """
290         cs = CONTEXT.getCurrentStep()
291         if self.parent != cs:
292             raise AsException("L'etape courante", cs.nom, cs,
293                               "devrait etre le parent de", self.nom, self)
294         else:
295             CONTEXT.unsetCurrentStep()
296             CONTEXT.setCurrentStep(self)
297
298     def resetCurrentStep(self):
299         """
300               Methode utilisee par l'etape self qui remet son etape parent comme
301               etape courante
302         """
303         cs = CONTEXT.getCurrentStep()
304         if self != cs:
305             raise AsException("L'etape courante", cs.nom, cs,
306                               "devrait etre", self.nom, self)
307         else:
308             CONTEXT.unsetCurrentStep()
309             CONTEXT.setCurrentStep(self.parent)
310
311     def issubstep(self, etape):
312         """
313             Cette methode retourne un entier indiquant si etape est une
314             sous etape de self ou non
315             1 = oui
316             0 = non
317             Une etape simple n'a pas de sous etape
318         """
319         return 0
320
321     def getFile(self, unite=None, fic_origine='', fname=None):
322         """
323             Retourne le nom du fichier correspondant a un numero d'unite
324             logique (entier) ainsi que le source contenu dans le fichier
325         """
326         if self.jdc:
327             return self.jdc.getFile(unite=unite, fic_origine=fic_origine, fname=fname)
328         else:
329             if unite != None:
330                 if os.path.exists("fort." + str(unite)):
331                     fname = "fort." + str(unite)
332             if fname == None:
333                 raise AsException("Impossible de trouver le fichier correspondant"
334                                   " a l unite %s" % unite)
335             if not os.path.exists(fname):
336                 raise AsException("%s n'est pas un fichier existant" % unite)
337             fproc = open(fname, 'r')
338             text = fproc.read()
339             fproc.close()
340             text = text.replace('\r\n', '\n')
341             linecache.cache[fname] = 0, 0, text.split('\n'), fname
342             return fname, text
343
344     def accept(self, visitor):
345         """
346            Cette methode permet de parcourir l'arborescence des objets
347            en utilisant le pattern VISITEUR
348         """
349         visitor.visitETAPE(self)
350
351     def updateContext(self, d):
352         """
353             Cette methode doit updater le contexte fournit par
354             l'appelant en argument (d) en fonction de sa definition
355         """
356         if type(self.definition.op_init) == types.FunctionType:
357             self.definition.op_init(*(self, d))
358         if self.sd:
359             d[self.sd.nom] = self.sd
360
361     def copy(self):
362         """ Methode qui retourne une copie de self non enregistree auprès du JDC
363             et sans sd
364         """
365         etape = copy(self)
366         etape.sd = None
367         etape.state = 'modified'
368         etape.reuse = None
369         etape.sdnom = None
370         etape.etape = etape
371         etape.mcListe = []
372         for objet in self.mcListe:
373             new_obj = objet.copy()
374             new_obj.reparent(etape)
375             etape.mcListe.append(new_obj)
376         return etape
377
378     def copyReuse(self, old_etape):
379         """ Methode qui copie le reuse d'une autre etape.
380         """
381         if hasattr(old_etape, "reuse"):
382             self.reuse = old_etape.reuse
383
384     def copySdnom(self, old_etape):
385         """ Methode qui copie le sdnom d'une autre etape.
386         """
387         if hasattr(old_etape, "sdnom"):
388             self.sdnom = old_etape.sdnom
389
390     def reparent(self, parent):
391         """
392             Cette methode sert a reinitialiser la parente de l'objet
393         """
394         self.parent = parent
395         self.jdc = parent.getJdcRoot()
396         self.etape = self
397         for mocle in self.mcListe:
398             mocle.reparent(self)
399         if self.sd and self.reuse == None:
400             self.sd.jdc = self.jdc
401
402     def getCmd(self, nomcmd):
403         """
404             Methode pour recuperer la definition d'une commande
405             donnee par son nom dans les catalogues declares
406             au niveau du jdc
407             Appele par un ops d'une macro en Python
408         """
409         return self.jdc.getCmd(nomcmd)
410
411     def copyIntern(self, etape):
412         """
413             Methode permettant lors du processus de recopie de copier
414             les elements internes d'une etape dans une autre
415         """
416         return
417
418     def fullCopy(self, parent=None):
419         """
420            Methode permettant d'effectuer une copie complète
421            d'une etape (y compris concept produit, elements internes)
422            Si l'argument parent est fourni, la nouvelle etape
423            aura cet objet comme parent.
424         """
425         new_etape = self.copy()
426         new_etape.copyReuse(self)
427         new_etape.copySdnom(self)
428         if parent:
429             new_etape.reparent(parent)
430         if self.sd:
431             new_sd = self.sd.__class__(etape=new_etape)
432             new_etape.sd = new_sd
433             if self.reuse == None:
434                 new_etape.parent.NommerSdprod(new_sd, self.sd.nom)
435             else:
436                 new_sd.setName(self.sd.nom)
437         new_etape.copyIntern(self)
438         return new_etape
439
440     def resetJdc(self, new_jdc):
441         """
442            Reinitialise le nommage du concept de l'etape lors d'un changement de jdc
443         """
444         if self.sd and self.reuse == None:
445             self.parent.NommerSdprod(self.sd, self.sd.nom)
446
447     def isInclude(self):
448         """Permet savoir si on a affaire a la commande INCLUDE
449         car le comportement de ces macros est particulier.
450         """
451         return self.nom.startswith('INCLUDE')
452
453     def sdAccessible(self):
454         """Dit si on peut acceder aux "valeurs" (jeveux) de l'ASSD produite par l'etape.
455         """
456         if CONTEXT.debug:
457             print(('`- ETAPE sdAccessible :', self.nom))
458         return self.parent.sdAccessible()
459
460     def getConcept(self, nomsd):
461         """
462             Methode pour recuperer un concept a partir de son nom
463         """
464         # pourrait etre appelee par une commande fortran faisant appel a des fonctions python
465         # on passe la main au parent
466         return self.parent.getConcept(nomsd)