Salome HOME
*** empty log message ***
[tools/eficas.git] / Noyau / N_MACRO_ETAPE.py
index 40559108b0a95f6327c1f8ab1f80519383a8a516..57a4b8ef9e9f692c46366760cf5698fff35dd3f9 100644 (file)
@@ -1,3 +1,26 @@
+#@ MODIF N_MACRO_ETAPE Noyau  DATE 14/09/2004   AUTEUR MCOURTOI M.COURTOIS 
+# -*- coding: iso-8859-1 -*-
+#            CONFIGURATION MANAGEMENT OF EDF VERSION
+# ======================================================================
+# COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
+# THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
+# IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
+# THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR   
+# (AT YOUR OPTION) ANY LATER VERSION.                                 
+#
+# THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT 
+# WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF          
+# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU    
+# GENERAL PUBLIC LICENSE FOR MORE DETAILS.                            
+#
+# YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE   
+# ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,       
+#    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.      
+#                                                                       
+#                                                                       
+# ======================================================================
+
+
 """ 
     Ce module contient la classe MACRO_ETAPE qui sert à vérifier et à exécuter
     une commande
@@ -87,6 +110,7 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
 
       """
       if not self.isactif():return
+      self.sdnom=nom
       try:
          # On positionne la macro self en tant que current_step pour que les 
          # étapes créées lors de l'appel à sd_prod et à op_init aient la macro
@@ -103,15 +127,13 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
                # d un concept
                sd.nom=nom
          self.reset_current_step()
-         if self.jdc and self.jdc.par_lot == "NON" :
-            self.Execute()
-         return sd
       except AsException,e:
          self.reset_current_step()
          raise AsException("Etape ",self.nom,'ligne : ',self.appel[0],
                               'fichier : ',self.appel[1],e)
-      except EOFError:
-         #self.reset_current_step()
+      except (EOFError,self.jdc.UserError):
+         # Le retablissement du step courant n'est pas strictement necessaire. On le fait pour des raisons de coherence
+         self.reset_current_step()
          raise
       except :
          self.reset_current_step()
@@ -120,6 +142,9 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
                            'fichier : ',self.appel[1]+'\n',
                             string.join(l))
 
+      self.Execute()
+      return sd
+
    def get_sd_prod(self):
       """
         Retourne le concept résultat d'une macro étape
@@ -146,7 +171,7 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
           # les concepts produits dans self.sdprods, il faut le mettre à zéro avant de l'appeler
           self.sdprods=[]
           sd_prod= apply(sd_prod,(self,),d)
-        except EOFError:
+        except (EOFError,self.jdc.UserError):
           raise
         except:
           if CONTEXT.debug: traceback.print_exc()
@@ -154,9 +179,9 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
           raise AsException("impossible d affecter un type au resultat\n",string.join(l[2:]))
 
       # on teste maintenant si la SD est réutilisée ou s'il faut la créer
-      if self.reuse:
-        if AsType(self.reuse) != sd_prod:
-          raise AsException("type de concept reutilise incompatible avec type produit")
+      if self.definition.reentrant != 'n' and self.reuse:
+        # Le concept produit est specifie reutilise (reuse=xxx). C'est une erreur mais non fatale.
+        # Elle sera traitee ulterieurement.
         self.sd=self.reuse
       else:
         if sd_prod == None:
@@ -164,8 +189,8 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
         else:
           self.sd= sd_prod(etape=self)
           self.typret=sd_prod
-        if self.definition.reentrant == 'o':
-          self.reuse = self.sd
+          # Si la commande est obligatoirement reentrante et reuse n'a pas ete specifie, c'est une erreur. 
+          # On ne fait rien ici. L'erreur sera traitee par la suite. 
       return self.sd
 
    def get_type_produit(self,force=0):
@@ -206,7 +231,11 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
       # mémorisée dans self.index_etape_courante
       # Si on insère des commandes (par ex, dans EFICAS), il faut
       # préalablement remettre ce pointeur à 0
-      index_etape=self.etapes.index(etape)
+      if etape:
+         index_etape=self.etapes.index(etape)
+      else:
+         index_etape=len(self.etapes)
+
       if index_etape >= self.index_etape_courante:
          # On calcule le contexte en partant du contexte existant
          d=self.current_context
@@ -226,7 +255,7 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
    def supprime(self):
       """
          Méthode qui supprime toutes les références arrières afin que 
-         l'objet puisse être correctement détruit par le garbage collector
+         l'objet puisse etre correctement détruit par le garbage collector
       """
       N_MCCOMPO.MCCOMPO.supprime(self)
       self.jdc=None
@@ -332,35 +361,65 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
             raise AsException("Le type du concept produit %s devrait etre une sur classe de %s" %(sd.__class__,sdprod))
          # La propriete du concept est transferee a l'etape avec le type attendu par l'étape
          etape.sd=sd
-         #sd.__call__=sdprod
-         #XXX Il semble plus logique que ce soit class et non pas call ???
-         sd.__class__=sdprod
          sd.etape=etape
+         # On donne au concept le type produit par la sous commande.
+         # Le principe est le suivant : apres avoir verifie que le type deduit par la sous commande
+         # est bien coherent avec celui initialement affecte par la macro (voir ci dessus)
+         # on affecte au concept ce type car il peut etre plus precis (derive, en general)
+         sd.__class__=sdprod
+         # On force également le nom stocké dans l'attribut sdnom : on lui donne le nom 
+         # du concept associé à nomsd
+         etape.sdnom=sd.nom
+      elif etape.definition.reentrant != 'n' and etape.reuse != None:
+         # On est dans le cas d'une commande avec reutilisation d'un concept existant
+         # get_sd_prod fait le necessaire : verifications, associations, etc. mais ne cree 
+         # pas un nouveau concept. Il retourne le concept reutilise
+         sd= etape.get_sd_prod()
+         # Dans le cas d'un concept nomme automatiquement : _xxx, __xxx,
+         # On force le nom stocke dans l'attribut sdnom  de l'objet etape : on lui donne le nom 
+         # du concept  reutilise (sd ou etape.reuse c'est pareil)
+         # Ceci est indispensable pour eviter des erreurs lors des verifications des macros
+         # En effet une commande avec reutilisation d'un concept verifie que le nom de 
+         # la variable a gauche du signe = est le meme que celui du concept reutilise.
+         # Lorsqu'une telle commande apparait dans une macro, on supprime cette verification.
+         if (etape.sdnom == '' or etape.sdnom[0] == '_'):
+            etape.sdnom=sd.nom
       else:
+         # On est dans le cas de la creation d'un nouveau concept
          sd= etape.get_sd_prod()
-         if sd != None and etape.reuse == None:
-            # ATTENTION : On ne nomme la SD que dans le cas de non reutilisation d un concept
+         if sd != None :
             self.NommerSdprod(sd,nomsd)
       return sd
 
-   def NommerSdprod(self,sd,sdnom):
+   def NommerSdprod(self,sd,sdnom,restrict='non'):
       """ 
           Cette methode est appelee par les etapes internes de la macro
           La macro appelle le JDC pour valider le nommage
           On considere que l espace de nom est unique et géré par le JDC
           Si le nom est deja utilise, l appel leve une exception
+          Si restrict=='non', on insere le concept dans le contexte de la macro
+          Si restrict=='oui', on n'insere pas le concept dans le contexte de la macro
       """
+      # Normalement, lorsqu'on appelle cette methode, on ne veut nommer que des concepts nouvellement crees.
+      # Le filtrage sur les concepts a creer ou a ne pas creer est fait dans la methode
+      # create_sdprod. La seule chose a verifier apres conversion eventuelle du nom
+      # est de verifier que le nom n'est pas deja attribue. Ceci est fait en delegant
+      # au JDC par l'intermediaire du parent.
+
       #XXX attention inconsistence : prefix et gcncon ne sont pas 
       # définis dans le package Noyau. La methode NommerSdprod pour
       # les macros devrait peut etre etre déplacée dans Build ???
+
       if CONTEXT.debug : print "MACRO.NommerSdprod: ",sd,sdnom
+
       if hasattr(self,'prefix'):
         # Dans le cas de l'include_materiau on ajoute un prefixe au nom du concept
         if sdnom != self.prefix:sdnom=self.prefix+sdnom
+
       if self.Outputs.has_key(sdnom):
         # Il s'agit d'un concept de sortie de la macro produit par une sous commande
         sdnom=self.Outputs[sdnom].nom
-      elif sdnom[0] == '_':
+      elif sdnom != '' and sdnom[0] == '_':
         # Si le nom du concept commence par le caractere _ on lui attribue
         # un identificateur JEVEUX construit par gcncon et respectant
         # la regle gcncon legerement adaptee ici
@@ -377,14 +436,21 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
           sdnom=self.gcncon('.')
         else:
           sdnom=self.gcncon('_')
-      if self.sd != None and self.sd.nom == sdnom :
-        # Il s'agit du concept produit par la macro, il a deja ete nomme.
-        # On se contente de donner le meme nom au concept produit par la sous commande
-        # sans passer par la routine de nommage
-        sd.nom=sdnom
       else:
-        # On propage le nommage au contexte superieur
-        self.parent.NommerSdprod(sd,sdnom)
+        # On est dans le cas d'un nom de concept global. 
+        pass
+
+      if restrict == 'non':
+         # On demande le nommage au parent mais sans ajout du concept dans le contexte du parent
+         # car on va l'ajouter dans le contexte de la macro
+         self.parent.NommerSdprod(sd,sdnom,restrict='oui')
+         # On ajoute dans le contexte de la macro les concepts nommes
+         # Ceci est indispensable pour les CO (macro) dans un INCLUDE
+         self.g_context[sdnom]=sd
+      else:
+         # La demande de nommage vient probablement d'une macro qui a mis
+         # le concept dans son contexte. On ne traite plus que le nommage (restrict="oui")
+         self.parent.NommerSdprod(sd,sdnom,restrict='oui')
 
    def delete_concept_after_etape(self,etape,sd):
       """
@@ -429,7 +495,10 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
       """
           Inclut un fichier poursuite
       """
-      f,text=self.get_file(fic_origine=self.parent.nom)
+      try:
+         f,text=self.get_file(fic_origine=self.parent.nom)
+      except:
+         raise AsException("Impossible d'ouvrir la base pour une poursuite")
       self.fichier_init=f
       if f == None:return
       self.make_contexte(f,text)
@@ -448,7 +517,51 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
       d={}
       self.g_context = d
       self.contexte_fichier_init = d
-      exec code in self.parent.g_context,d
+      globs=self.parent.get_global_contexte()
+      exec code in globs,d
+
+   def get_global_contexte(self):
+      """
+          Cette methode retourne le contexte global fourni
+          par le parent(self) a une etape fille (l'appelant) pour
+          realiser des evaluations de texte Python (INCLUDE,...)
+      """
+      # Le contexte global est forme par concatenation du contexte
+      # du parent de self et de celui de l'etape elle meme (self)
+      d=self.parent.get_global_contexte()
+      d.update(self.g_context)
+      return d
+
+   def copy(self):
+      """ Méthode qui retourne une copie de self non enregistrée auprès du JDC
+          et sans sd
+          On surcharge la methode de ETAPE pour exprimer que les concepts crees
+          par la MACRO d'origine ne sont pas crees par la copie mais eventuellement
+          seulement utilises
+      """
+      etape=N_ETAPE.ETAPE.copy(self)
+      etape.sdprods=[]
+      return etape
+
+   def copy_intern(self,etape):
+      """ Cette méthode effectue la recopie des etapes internes d'une macro 
+          passée en argument (etape)
+      """
+      self.etapes=[]
+      for etp in etape.etapes:
+          new_etp=etp.copy()
+          new_etp.copy_reuse(etp)
+          new_etp.copy_sdnom(etp)
+          new_etp.reparent(self)
+          if etp.sd:
+             new_sd = etp.sd.__class__(etape=new_etp)
+             new_etp.sd = new_sd
+             if etp.reuse:
+                new_sd.nom = etp.sd.nom
+             else:
+                self.NommerSdprod(new_sd,etp.sd.nom)
+          new_etp.copy_intern(etp)
+          self.etapes.append(new_etp)