]> SALOME platform Git repositories - tools/eficas.git/blob - Noyau/N_JDC.py
Salome HOME
CCAR: Mise a niveau Noyau avec Aster 7.2.11 + correction bug sur les blocs
[tools/eficas.git] / Noyau / N_JDC.py
1 #@ MODIF N_JDC Noyau  DATE 05/11/2003   AUTEUR CAMBIER S.CAMBIER 
2 #            CONFIGURATION MANAGEMENT OF EDF VERSION
3 # ======================================================================
4 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
5 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
6 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
7 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR   
8 # (AT YOUR OPTION) ANY LATER VERSION.                                 
9 #
10 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT 
11 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF          
12 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU    
13 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.                            
14 #
15 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE   
16 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,       
17 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.      
18 #                                                                       
19 #                                                                       
20 # ======================================================================
21 """
22    Ce module contient la classe JDC qui sert à interpréter un jeu de commandes
23 """
24
25 # Modules Python
26 import os,string,traceback
27 import types,sys,linecache
28
29 # Modules EFICAS
30 import N_OBJECT
31 import N_CR
32 from N_Exception import AsException
33 from N_ASSD import ASSD
34
35 class JDC(N_OBJECT.OBJECT):
36    """
37       Cette classe interprete un jeu de commandes fourni sous
38       la forme d'une chaine de caractères
39
40       Attributs de classe :
41
42       Attributs d'instance :
43
44    """
45    nature = "JDC"
46    CR=N_CR.CR
47    exec_init="""
48 import Accas
49 from Accas import _F
50 from Accas import *
51 NONE = None
52 """
53
54    from N_utils import SEP
55
56    def __init__(self,definition=None,procedure=None,cata=None,
57                      cata_ord_dico=None,parent=None,
58                      nom='SansNom',appli=None,context_ini=None,**args):
59       self.procedure=procedure
60       self.definition = definition
61       self.cata=cata
62       if type(self.cata) != types.TupleType and cata != None: 
63          self.cata=(self.cata,)
64       self.cata_ordonne_dico=cata_ord_dico
65       self.nom = nom
66       self.appli=appli
67       self.parent=parent
68       self.context_ini=context_ini
69       # On conserve les arguments supplémentaires. Il est possible de passer 
70       # des informations globales au JDC par ce moyen. Il pourrait etre plus 
71       # sur de mettre en place le mecanisme des mots-cles pour verifier la 
72       # validité des valeurs passées.
73       # Ceci reste à faire
74       # On initialise avec les parametres de la definition puis on 
75       # update avec ceux du JDC
76       self.args=self.definition.args
77       self.args.update(args)
78       self.nstep=0
79       self.nsd=0
80       self.par_lot='OUI'
81       if definition:
82          self.regles=definition.regles
83          self.code = definition.code
84       else:
85          self.regles=()
86          self.code = "CODE"
87       #
88       #  Creation de l objet compte rendu pour collecte des erreurs
89       #
90       self.cr = self.CR(debut = "CR phase d'initialisation", 
91                         fin = "fin CR phase d'initialisation")
92       self.g_context={}
93       # Liste pour stocker tous les concepts produits dans le JDC
94       self.sds=[]
95       # Dictionnaire pour stocker tous les concepts du JDC (acces rapide par le nom)
96       self.sds_dict={}
97       self.etapes=[]
98       self.mc_globaux={}
99       self.current_context={}
100       self.condition_context={}
101       self.index_etape_courante=0
102       self.UserError="UserError"
103       self.alea = None
104
105    def compile(self):
106       """
107          Cette methode compile la chaine procedure
108          Si des erreurs se produisent, elles sont consignées dans le 
109          compte-rendu self.cr
110       """
111       try:
112         if self.appli != None : 
113            self.appli.affiche_infos('Compilation du fichier de commandes \
114                                      en cours ...')
115         self.proc_compile=compile(self.procedure,self.nom,'exec')
116       except SyntaxError,e:
117         if CONTEXT.debug : traceback.print_exc()
118         l=traceback.format_exception_only(SyntaxError,e)
119         self.cr.exception("Compilation impossible : "+string.join(l))
120       return
121
122    def exec_compile(self):
123       """
124          Cette méthode execute le jeu de commandes compilé dans le contexte
125          self.g_context de l'objet JDC
126       """
127       CONTEXT.set_current_step(self)
128       # Le module nommage utilise le module linecache pour accéder
129       # au source des commandes du jeu de commandes.
130       # Dans le cas d'un fichier, on accède au contenu de ce fichier
131       # Dans le cas d'une chaine de caractères il faut accéder
132       # aux commandes qui sont dans la chaine
133       import linecache
134       linecache.cache[self.nom]=0,0,string.split(self.procedure,'\n'),self.nom
135       try:
136          exec self.exec_init in self.g_context
137          for obj_cata in self.cata:
138             if type(obj_cata) == types.ModuleType :
139                init2 = "from "+obj_cata.__name__+" import *"
140                exec init2 in self.g_context
141
142          # Initialisation du contexte global pour l'évaluation des conditions de BLOC
143          # On utilise une copie de l'initialisation du contexte du jdc
144          self.condition_context=self.g_context.copy()
145
146          # Si l'attribut context_ini n'est pas vide, on ajoute au contexte global
147          # le contexte initial (--> permet d'évaluer un JDC en récupérant un contexte
148          # d'un autre par exemple)
149          if self.context_ini :
150             self.g_context.update(self.context_ini)
151             # Update du dictionnaire des concepts
152             for sdnom,sd in self.context_ini.items():
153                if isinstance(sd,ASSD):self.sds_dict[sdnom]=sd
154
155          if self.appli != None : 
156             self.appli.affiche_infos('Interprétation du fichier de \
157                                       commandes en cours ...')
158          # On sauve le contexte pour garder la memoire des constantes
159          # En mode edition (EFICAS) ou lors des verifications le contexte 
160          # est recalculé
161          # mais les constantes sont perdues
162          self.const_context=self.g_context
163          exec self.proc_compile in self.g_context
164
165          CONTEXT.unset_current_step()
166          if self.appli != None : self.appli.affiche_infos('')
167
168       except EOFError:
169         # Exception utilise pour interrompre un jeu
170         # de commandes avant la fin
171         # Fonctionnement normal, ne doit pas etre considere comme une erreur
172         CONTEXT.unset_current_step()
173
174       except AsException,e:
175         # une erreur a ete identifiee
176         if CONTEXT.debug :
177           traceback.print_exc()
178         self.cr.exception(str(e))
179         CONTEXT.unset_current_step()
180
181       except NameError,e:
182         etype, value, tb = sys.exc_info()
183         l= traceback.extract_tb(tb)
184         s= traceback.format_exception_only("Erreur de nom",e)[0][:-1]
185         message = "erreur de syntaxe,  %s ligne %d" % (s,l[-1][1])
186         if CONTEXT.debug :
187           traceback.print_exc()
188         self.cr.exception(message)
189         CONTEXT.unset_current_step()
190
191       except self.UserError,exc_val:
192         self.traiter_user_exception(exc_val)
193         CONTEXT.unset_current_step()
194     
195       except :
196         # erreur inattendue
197         # sys_exc_typ,sys_exc_value,sys_exc_frame = sys_exc.info() 
198         # (tuple de 3 éléments)
199         if CONTEXT.debug : traceback.print_exc()
200
201         exc_typ,exc_val,exc_fr=sys.exc_info()
202         l=traceback.format_exception(exc_typ,exc_val,exc_fr)
203         self.cr.exception("erreur non prevue et non traitee prevenir la maintenance "+
204                            self.nom+'\n'+ string.join(l))
205         del exc_typ,exc_val,exc_fr
206         CONTEXT.unset_current_step()
207
208    def traiter_user_exception(self,exc_val):
209        """Cette methode realise un traitement sur les exceptions utilisateur    
210           Par defaut il n'y a pas de traitement. La méthode doit etre 
211           surchargée pour en introduire un.
212        """
213        return 
214
215    def register(self,etape):
216       """
217          Cette méthode ajoute etape dans la liste des etapes : self.etapes
218          et retourne un numéro d'enregistrement
219       """
220       self.etapes.append(etape)
221       return self.g_register(etape)
222
223    def o_register(self,sd):
224       """
225          Retourne un identificateur pour concept
226       """
227       self.nsd=self.nsd+1
228       nom=sd.idracine + self.SEP + `self.nsd`
229       return nom
230
231    def g_register(self,etape):
232       """
233           Retourne un identificateur pour etape
234       """
235       self.nstep=self.nstep+1
236       idetape=etape.idracine + self.SEP + `self.nstep`
237       return idetape
238
239    def create_sdprod(self,etape,nomsd):
240       """ 
241           Intention : Cette methode doit fabriquer le concept produit retourne
242                   par l'etape etape et le nommer.
243                   Elle est appelée à l'initiative de l'etape
244                   pendant le processus de construction de cette etape : 
245                     methode __call__ de la classe CMD (OPER ou MACRO)
246                   Ce travail est réalisé par le contexte supérieur 
247                   (etape.parent) car dans certains cas, le concept ne doit 
248                   pas etre fabriqué mais l'etape doit simplement utiliser 
249                   un concept préexistant.
250                   Cas 1 : etape.reuse != None : le concept est réutilisé
251                   Cas 2 : l'étape appartient à une macro qui a déclaré un 
252                           concept de sortie qui doit etre produit par cette 
253                           etape.
254                   Dans le cas du JDC, le deuxième cas ne peut pas se produire.
255       """
256       sd= etape.get_sd_prod()
257       if sd != None and (etape.definition.reentrant == 'n' or etape.reuse is None) :
258          # ATTENTION : On ne nomme la SD que dans le cas de non reutilisation 
259          # d un concept. Commande non reentrante ou reuse absent.
260          self.NommerSdprod(sd,nomsd)
261       return sd
262
263    def NommerSdprod(self,sd,sdnom,restrict='non'):
264       """ 
265           Nomme la SD apres avoir verifie que le nommage est possible : nom 
266           non utilise
267           Si le nom est deja utilise, leve une exception
268           Met le concept créé dans le concept global g_context
269       """
270       if CONTEXT.debug : print "JDC.NommerSdprod ",sd,sdnom
271
272       o=self.sds_dict.get(sdnom,None)
273       if isinstance(o,ASSD):
274          raise AsException("Nom de concept deja defini : %s" % sdnom)
275
276       # ATTENTION : Il ne faut pas ajouter sd dans sds car il s y trouve deja.
277       # Ajoute a la creation (appel de reg_sd).
278       self.sds_dict[sdnom]=sd
279       sd.nom=sdnom
280
281       # En plus si restrict vaut 'non', on insere le concept dans le contexte du JDC
282       if restrict == 'non':
283          self.g_context[sdnom]=sd
284
285    def reg_sd(self,sd):
286       """ 
287           Methode appelee dans l __init__ d un ASSD lors de sa creation 
288           pour s enregistrer
289       """
290       self.sds.append(sd)
291       return self.o_register(sd)
292
293    def delete_concept_after_etape(self,etape,sd):
294       """
295           Met à jour les étapes du JDC qui sont après etape suite à
296           la disparition du concept sd
297       """
298       # Cette methode est définie dans le noyau mais ne sert que pendant 
299       # la phase de creation des etapes et des concepts. Il n'y a aucun 
300       # traitement particulier à réaliser.
301       # Dans d'autres conditions, il faut surcharger cette méthode
302       return
303
304    def supprime(self):
305       N_OBJECT.OBJECT.supprime(self)
306       for etape in self.etapes:
307          etape.supprime()
308
309    def get_file(self,unite=None,fic_origine=''):
310       """
311           Retourne le nom du fichier correspondant à un numero d'unité 
312           logique (entier) ainsi que le source contenu dans le fichier
313       """
314       if self.appli :
315          # Si le JDC est relié à une application maitre, on délègue la recherche
316          file= self.appli.get_file(unite,fic_origine)
317       else:
318          file = None
319          if unite != None:
320             if os.path.exists("fort."+str(unite)):
321                file= "fort."+str(unite)
322          if file == None :
323             raise AsException("Impossible de trouver le fichier correspondant"
324                                " a l unite %s" % unite)
325          if not os.path.exists(file):
326             raise AsException("%s n'est pas un fichier existant" % unite)
327          fproc=open(file,'r')
328          text=fproc.read()
329          fproc.close()
330       if file == None : return None,None
331       text=string.replace(text,'\r\n','\n')
332       linecache.cache[file]=0,0,string.split(text,'\n'),file
333       return file,text
334
335    def set_par_lot(self,par_lot):
336       """ 
337           Met le mode de traitement a PAR LOT 
338           ou a COMMANDE par COMMANDE
339           en fonction de la valeur du mot cle PAR_LOT et 
340           du contexte : application maitre ou pas
341       """
342       if self.appli == None:
343         # Pas d application maitre
344         self.par_lot=par_lot
345       else:
346         # Avec application maitre
347         self.par_lot='OUI'
348
349    def accept(self,visitor):
350       """
351          Cette methode permet de parcourir l'arborescence des objets
352          en utilisant le pattern VISITEUR
353       """
354       visitor.visitJDC(self)
355
356    def interact(self):
357       """
358           Cette methode a pour fonction d'ouvrir un interpreteur 
359           pour que l'utilisateur entre des commandes interactivement
360       """
361       CONTEXT.set_current_step(self)
362       try:
363          # Le module nommage utilise le module linecache pour accéder
364          # au source des commandes du jeu de commandes.
365          # Dans le cas d'un fichier, on accède au contenu de ce fichier
366          # Dans le cas de la console interactive, il faut pouvoir accéder
367          # aux commandes qui sont dans le buffer de la console
368          import linecache,code
369          console= code.InteractiveConsole(self.g_context,filename="<console>")
370          linecache.cache["<console>"]=0,0,console.buffer,"<console>"
371          banner="""***********************************************
372 *          Interpreteur interactif %s
373 ***********************************************""" % self.code
374          console.interact(banner)
375       finally:
376          console=None
377          CONTEXT.unset_current_step()
378
379    def get_contexte_avant(self,etape):
380       """
381          Retourne le dictionnaire des concepts connus avant etape
382          On tient compte des commandes qui modifient le contexte
383          comme DETRUIRE ou les macros
384          Si etape == None, on retourne le contexte en fin de JDC
385       """
386       # L'étape courante pour laquelle le contexte a été calculé est 
387       # mémorisée dans self.index_etape_courante
388       # XXX on pourrait faire mieux dans le cas PAR_LOT="NON" : en 
389       # mémorisant l'étape
390       # courante pendant le processus de construction des étapes.
391       # Si on insère des commandes (par ex, dans EFICAS), il faut préalablement
392       # remettre ce pointeur à 0
393       if etape:
394          index_etape=self.etapes.index(etape)
395       else:
396          index_etape=len(self.etapes)
397       if index_etape >= self.index_etape_courante:
398          # On calcule le contexte en partant du contexte existant
399          d=self.current_context
400          if self.index_etape_courante==0 and self.context_ini:
401             d.update(self.context_ini)
402          liste_etapes=self.etapes[self.index_etape_courante:index_etape]
403       else:
404          d=self.current_context={}
405          if self.context_ini:d.update(self.context_ini)
406          liste_etapes=self.etapes
407
408       for e in liste_etapes:
409          if e is etape:
410             break
411          if e.isactif():
412             e.update_context(d)
413       self.index_etape_courante=index_etape
414       return d
415
416    def get_global_contexte(self):
417       return self.g_context.copy()
418
419    def get_cmd(self,nomcmd):
420       """
421           Méthode pour recuperer la definition d'une commande
422           donnee par son nom dans les catalogues declares
423           au niveau du jdc
424       """
425       for cata in self.cata:
426           if hasattr(cata,nomcmd):
427              return getattr(cata,nomcmd)
428