X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=Noyau%2FN_MACRO_ETAPE.py;h=87c14e47e98dde6455c1ea1878f2669caf22ad98;hb=a7d5f18fe322c770026b50343adc09ed0472c192;hp=40559108b0a95f6327c1f8ab1f80519383a8a516;hpb=fcd054a825fbe171652108194c0204f8e3fd955a;p=tools%2Feficas.git diff --git a/Noyau/N_MACRO_ETAPE.py b/Noyau/N_MACRO_ETAPE.py index 40559108..87c14e47 100644 --- a/Noyau/N_MACRO_ETAPE.py +++ b/Noyau/N_MACRO_ETAPE.py @@ -1,3 +1,26 @@ +#@ 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 +# 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 @@ -13,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 : @@ -59,6 +84,7 @@ class MACRO_ETAPE(N_ETAPE.ETAPE): self.actif=1 self.sdprods=[] self.make_register() + self.UserError="UserError" def make_register(self): """ @@ -69,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): """ @@ -87,6 +115,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 +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() @@ -120,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 @@ -138,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: @@ -146,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() @@ -154,9 +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: - 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,11 +208,18 @@ 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): + 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) @@ -181,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 @@ -206,7 +256,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 +280,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 @@ -249,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): @@ -324,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 @@ -332,35 +441,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 +516,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 +575,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 +597,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)