]> SALOME platform Git repositories - tools/eficas.git/blobdiff - Noyau/N_MACRO_ETAPE.py
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
 #            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
 """ 
     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_Exception import AsException
 import N_utils
 from N_utils import AsType
+from N_CO import CO
 
 class MACRO_ETAPE(N_ETAPE.ETAPE):
    """
 
    """
    nature = "COMMANDE"
 
 class MACRO_ETAPE(N_ETAPE.ETAPE):
    """
 
    """
    nature = "COMMANDE"
+   typeCO=CO
    def __init__(self,oper=None,reuse=None,args={}):
       """
          Attributs :
    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.actif=1
       self.sdprods=[]
       self.make_register()
+      self.UserError="UserError"
 
    def make_register(self):
       """
 
    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.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
       else:
          self.jdc = self.parent =None
          self.id=None
          self.niveau=None
+         self.UserError="UserError"
 
    def Build_sd(self,nom):
       """
 
    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()
                # 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 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()
          raise
       except :
          self.reset_current_step()
@@ -141,6 +147,20 @@ class MACRO_ETAPE(N_ETAPE.ETAPE):
                            'fichier : ',self.appel[1]+'\n',
                             string.join(l))
 
                            '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
    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
       """
       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:
       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)
           # 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()
           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
           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:
         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
         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):
       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)
       """
            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
                     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)
       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
       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
       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:
       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)
          co.etape=self
          co.__class__ = t
          self.sdprods.append(co)
+
       elif co.etape== self:
       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)
          self.sdprods.append(co)
+
       elif co.etape== self.parent:
       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
          # 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.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)
          self.sdprods.append(co)
+
       elif self.issubstep(co.etape):
       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)
          self.sdprods.append(co)
+
       else:
       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):
          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.
          # 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
          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
          # 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
          # 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.
          # 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
             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
       # 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 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
       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
         # 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
 
       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)
+