Salome HOME
CCAR: correction d'un probleme de mise a jour de contexte lors d'une insertion
[tools/eficas.git] / Noyau / N_MACRO_ETAPE.py
index d51031d184c496cd0c621eadd7c88381d55ceae6..87c14e47e98dde6455c1ea1878f2669caf22ad98 100644 (file)
@@ -1,4 +1,5 @@
-#@ MODIF N_MACRO_ETAPE Noyau  DATE 23/10/2002   AUTEUR DURAND C.DURAND 
+#@ MODIF N_MACRO_ETAPE Noyau  DATE 31/05/2005   AUTEUR DURAND C.DURAND 
+# -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
 # COPYRIGHT (C) 1991 - 2002  EDF R&D                  WWW.CODE-ASTER.ORG
@@ -18,6 +19,8 @@
 #                                                                       
 #                                                                       
 # ======================================================================
+
+
 """ 
     Ce module contient la classe MACRO_ETAPE qui sert à vérifier et à exécuter
     une commande
@@ -33,12 +36,14 @@ import N_ETAPE
 from N_Exception import AsException
 import N_utils
 from N_utils import AsType
+from N_CO import CO
 
 class MACRO_ETAPE(N_ETAPE.ETAPE):
    """
 
    """
    nature = "COMMANDE"
+   typeCO=CO
    def __init__(self,oper=None,reuse=None,args={}):
       """
          Attributs :
@@ -79,6 +84,7 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
       self.actif=1
       self.sdprods=[]
       self.make_register()
+      self.UserError="UserError"
 
    def make_register(self):
       """
@@ -89,10 +95,12 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
          self.jdc = self.parent.get_jdc_root()
          self.id=self.parent.register(self)
          self.niveau=None
+         self.UserError=self.jdc.UserError
       else:
          self.jdc = self.parent =None
          self.id=None
          self.niveau=None
+         self.UserError="UserError"
 
    def Build_sd(self,nom):
       """
@@ -124,15 +132,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.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()
@@ -141,6 +147,20 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
                            'fichier : ',self.appel[1]+'\n',
                             string.join(l))
 
+      self.Execute()
+      return sd
+
+   def mark_CO(self):
+      """
+         Marquage des concepts CO d'une macro-commande
+      """
+      # On marque les concepts CO pour verification ulterieure de leur bonne utilisation
+      l=self.get_all_co()
+      for c in l:
+          #if not hasattr(c,"_etape") or c._etape is not c.etape: 
+             c._etape=self
+      return l
+
    def get_sd_prod(self):
       """
         Retourne le concept résultat d'une macro étape
@@ -159,6 +179,9 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
       """
       sd_prod=self.definition.sd_prod
       self.typret=None
+      # On marque les concepts CO pour verification ulterieure de leur bonne utilisation
+      self.mark_CO()
+
       if type(self.definition.sd_prod) == types.FunctionType:
         d=self.cree_dict_valeurs(self.mc_liste)
         try:
@@ -167,7 +190,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.UserError):
           raise
         except:
           if CONTEXT.debug: traceback.print_exc()
@@ -175,10 +198,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:
-        # Il est preferable de traiter cette erreur ultérieurement : ce n'est pas une erreur fatale
-        #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:
@@ -186,12 +208,18 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
         else:
           self.sd= sd_prod(etape=self)
           self.typret=sd_prod
-        # Si reuse n'a pas ete donné, c'est une erreur. Ne pas corriger afin de la detecter ensuite
-        #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):
+      try:
+          return self.get_type_produit_brut(force)
+      except:
+          #traceback.print_exc()
+          return None
+
+   def get_type_produit_brut(self,force=0):
       """
            Retourne le type du concept résultat de l'étape et eventuellement type
             les concepts produits "à droite" du signe égal (en entrée)
@@ -204,16 +232,15 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
                     et on retourne son résultat
       """
       if not force and hasattr(self,'typret'): return self.typret
+      # On marque les concepts CO pour verification ulterieure de leur bonne utilisation
+      self.mark_CO()
+
       if type(self.definition.sd_prod) == types.FunctionType:
         d=self.cree_dict_valeurs(self.mc_liste)
-        try:
-          # Comme sd_prod peut invoquer la méthode type_sdprod qui ajoute
-          # les concepts produits dans self.sdprods, il faut le mettre à zéro
-          self.sdprods=[]
-          sd_prod= apply(self.definition.sd_prod,(self,),d)
-        except:
-          #traceback.print_exc()
-          return None
+        # Comme sd_prod peut invoquer la méthode type_sdprod qui ajoute
+        # les concepts produits dans self.sdprods, il faut le mettre à zéro
+        self.sdprods=[]
+        sd_prod= apply(self.definition.sd_prod,(self,),d)
       else:
         sd_prod=self.definition.sd_prod
       return sd_prod
@@ -276,32 +303,87 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
       if not hasattr(co,'etape'):
          # Le concept vaut None probablement. On ignore l'appel
          return
-
+      # 
+      # On cherche a discriminer les differents cas de typage d'un concept
+      # produit par une macro qui est specifie dans un mot cle simple.
+      # On peut passer plusieurs fois par type_sdprod ce qui explique
+      # le nombre important de cas.
+      #
+      # Cas 1 : Le concept est libre. Il vient d'etre cree par CO(nom)
+      # Cas 2 : Le concept est produit par la macro. On est deja passe par type_sdprod.
+      #         Cas semblable a Cas 1.
+      # Cas 3 : Le concept est produit par la macro englobante (parent). On transfere
+      #         la propriete du concept de la macro parent a la macro courante (self)
+      #         en verifiant que le type est valide
+      # Cas 4 : La concept est la propriete d'une etape fille. Ceci veut dire qu'on est
+      #         deja passe par type_sdprod et que la propriete a ete transfere a une 
+      #         etape fille. Cas semblable a Cas 3.
+      # Cas 5 : Le concept est produit par une etape externe a la macro.
+      #
       if co.etape == None:
-         # le concept est libre
+         # Cas 1 : le concept est libre
+         # On l'attache a la macro et on change son type dans le type demande
+         # Recherche du mot cle simple associe au concept
+         mcs=self.get_mcs_with_co(co)
+         if len(mcs) != 1:
+            raise AsException("""Erreur interne. 
+Il ne devrait y avoir qu'un seul mot cle porteur du concept CO (%s)""" % co)
+         mcs=mcs[0]
+         if not self.typeCO in mcs.definition.type:
+            raise AsException("""Erreur interne. 
+Impossible de changer le type du concept (%s). Le mot cle associe ne supporte pas CO mais seulement (%s)""" %(co,mcs.definition.type))
          co.etape=self
          co.__class__ = t
          self.sdprods.append(co)
+
       elif co.etape== self:
-         # le concept est produit par self
-         co.__class__ = t
+         # Cas 2 : le concept est produit par la macro (self)
+         # On est deja passe par type_sdprod (Cas 1 ou 3).
+         # Il suffit de le mettre dans la liste des concepts produits (self.sdprods)
+         # Le type du concept doit etre coherent avec le type demande (seulement derive)
+         if not isinstance(co,t):
+            raise AsException("""Erreur interne. 
+Le type demande (%s) et le type du concept (%s) devraient etre derives""" %(t,co.__class__))
          self.sdprods.append(co)
+
       elif co.etape== self.parent:
-         # le concept est produit par la macro superieure
-         # on transfere la propriete
-         # On verifie que le type du concept existant co.__class__ est un sur type de celui attendu
+         # Cas 3 : le concept est produit par la macro parente (self.parent)
+         # on transfere la propriete du concept a la macro fille
+         # et on change le type du concept comme demande
+         # Au prealable, on verifie que le concept existant (co) est une instance 
+         # possible du type demande (t)
          # Cette règle est normalement cohérente avec les règles de vérification des mots-clés
-         if not issubclass(t,co.__class__):
-            raise AsException("Le type du concept produit %s devrait etre une sur classe de %s" %(co.__class__,t))
+         if not isinstance(co,t):
+            raise AsException("""
+Impossible de changer le type du concept produit (%s) en (%s).
+Le type actuel (%s) devrait etre une classe derivee du nouveau type (%s)""" % (co,t,co.__class__,t))
+         mcs=self.get_mcs_with_co(co)
+         if len(mcs) != 1:
+            raise AsException("""Erreur interne. 
+Il ne devrait y avoir qu'un seul mot cle porteur du concept CO (%s)""" % co)
+         mcs=mcs[0]
+         if not self.typeCO in mcs.definition.type:
+            raise AsException("""Erreur interne. 
+Impossible de changer le type du concept (%s). Le mot cle associe ne supporte pas CO mais seulement (%s)""" %(co,mcs.definition.type))
          co.etape=self
-         co.__class__ = t
+         # On ne change pas le type car il respecte la condition isinstance(co,t)
+         #co.__class__ = t
          self.sdprods.append(co)
+
       elif self.issubstep(co.etape):
-         # Le concept est propriété d'une sous etape de self. Il doit etre considere
-         # comme produit par la macro => ajout dans self.sdprods
+         # Cas 4 : Le concept est propriété d'une sous etape de la macro (self). 
+         # On est deja passe par type_sdprod (Cas 3 ou 1).
+         # Il suffit de le mettre dans la liste des concepts produits (self.sdprods)
+         # Le type du concept et t doivent etre derives. 
+         # Il n'y a aucune raison pour que la condition ne soit pas verifiee.
+         if not isinstance(co,t):
+            raise AsException("""Erreur interne. 
+Le type demande (%s) et le type du concept (%s) devraient etre derives""" %(t,co.__class__))
          self.sdprods.append(co)
+
       else:
-         # le concept est produit par une autre étape
+         # Cas 5 : le concept est produit par une autre étape
+         # On ne fait rien
          return
 
    def issubstep(self,etape):
@@ -351,7 +433,7 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
          # Il s'agit d'un concept de sortie de la macro. Il ne faut pas le créer
          # Il faut quand meme appeler la fonction sd_prod si elle existe.
          # get_type_produit le fait et donne le type attendu par la commande pour verification ultérieure.
-         sdprod=etape.get_type_produit()
+         sdprod=etape.get_type_produit_brut()
          sd=self.Outputs[nomsd]
          # On verifie que le type du concept existant sd.__class__ est un sur type de celui attendu
          # Cette règle est normalement cohérente avec les règles de vérification des mots-clés
@@ -368,7 +450,7 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
          # 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.reuse != None:
+      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
@@ -380,7 +462,7 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
          # 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[0] == '_':
+         if (etape.sdnom == '' or etape.sdnom[0] == '_'):
             etape.sdnom=sd.nom
       else:
          # On est dans le cas de la creation d'un nouveau concept
@@ -409,6 +491,7 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
       # 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
@@ -416,7 +499,7 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
       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
@@ -529,6 +612,37 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
       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)
+