From: eficas <> Date: Thu, 29 Jan 2004 18:21:17 +0000 (+0000) Subject: CCAR: Mise a niveau Noyau avec Aster 7.2.11 + correction bug sur les blocs X-Git-Tag: CC01mar04fin~17 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=e4a24913be7d3a0aa54076f523946737ba5624c7;p=tools%2Feficas.git CCAR: Mise a niveau Noyau avec Aster 7.2.11 + correction bug sur les blocs + reintegration méthodes surchargées dans Ihm --- diff --git a/Noyau/N_ETAPE.py b/Noyau/N_ETAPE.py index cb968d3a..1e703ba0 100644 --- a/Noyau/N_ETAPE.py +++ b/Noyau/N_ETAPE.py @@ -361,3 +361,12 @@ class ETAPE(N_MCCOMPO.MCCOMPO): self.etape=self for mocle in self.mc_liste: mocle.reparent(self) + + def get_cmd(self,nomcmd): + """ + Méthode pour recuperer la definition d'une commande + donnee par son nom dans les catalogues declares + au niveau du jdc + Appele par un ops d'une macro en Python + """ + return self.jdc.get_cmd(nomcmd) diff --git a/Noyau/N_JDC.py b/Noyau/N_JDC.py index d538ca71..ee40f7ce 100644 --- a/Noyau/N_JDC.py +++ b/Noyau/N_JDC.py @@ -1,4 +1,4 @@ -#@ MODIF N_JDC Noyau DATE 26/09/2003 AUTEUR DURAND C.DURAND +#@ MODIF N_JDC Noyau DATE 05/11/2003 AUTEUR CAMBIER S.CAMBIER # CONFIGURATION MANAGEMENT OF EDF VERSION # ====================================================================== # COPYRIGHT (C) 1991 - 2002 EDF R&D WWW.CODE-ASTER.ORG @@ -100,6 +100,7 @@ NONE = None self.condition_context={} self.index_etape_courante=0 self.UserError="UserError" + self.alea = None def compile(self): """ @@ -323,9 +324,11 @@ NONE = None " a l unite %s" % unite) if not os.path.exists(file): raise AsException("%s n'est pas un fichier existant" % unite) - fproc=open(file,'r') - text=string.replace(fproc.read(),'\r\n','\n') - fproc.close() + fproc=open(file,'r') + text=fproc.read() + fproc.close() + if file == None : return None,None + text=string.replace(text,'\r\n','\n') linecache.cache[file]=0,0,string.split(text,'\n'),file return file,text @@ -394,9 +397,12 @@ NONE = None if index_etape >= self.index_etape_courante: # On calcule le contexte en partant du contexte existant d=self.current_context + if self.index_etape_courante==0 and self.context_ini: + d.update(self.context_ini) liste_etapes=self.etapes[self.index_etape_courante:index_etape] else: d=self.current_context={} + if self.context_ini:d.update(self.context_ini) liste_etapes=self.etapes for e in liste_etapes: @@ -409,3 +415,14 @@ NONE = None def get_global_contexte(self): return self.g_context.copy() + + def get_cmd(self,nomcmd): + """ + Méthode pour recuperer la definition d'une commande + donnee par son nom dans les catalogues declares + au niveau du jdc + """ + for cata in self.cata: + if hasattr(cata,nomcmd): + return getattr(cata,nomcmd) + diff --git a/Noyau/N_MACRO_ETAPE.py b/Noyau/N_MACRO_ETAPE.py index 953b0d94..d663047e 100644 --- a/Noyau/N_MACRO_ETAPE.py +++ b/Noyau/N_MACRO_ETAPE.py @@ -529,6 +529,17 @@ 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 + diff --git a/Noyau/N_MCBLOC.py b/Noyau/N_MCBLOC.py index 60f3c80d..34fdb45e 100644 --- a/Noyau/N_MCBLOC.py +++ b/Noyau/N_MCBLOC.py @@ -81,15 +81,38 @@ class MCBLOC(N_MCCOMPO.MCCOMPO): """ dico={} - for v in self.mc_liste: - val = v.get_valeur() - if type(val)==types.DictionaryType: - for i,w in val.items(): - dico[i]=w - else : - dico[v.nom]=val + for mocle in self.mc_liste: + if mocle.isBLOC(): + # Si mocle est un BLOC, on inclut ses items dans le dictionnaire + # représentatif de la valeur de self. Les mots-clés fils de blocs sont + # donc remontés au niveau supérieur. + dico.update(mocle.get_valeur()) + else: + dico[mocle.nom]=mocle.get_valeur() + + # On rajoute tous les autres mots-clés locaux possibles avec la valeur + # par défaut ou None + # Pour les mots-clés facteurs, on ne traite que ceux avec statut défaut ('d') + # et caché ('c') + # On n'ajoute aucune information sur les blocs. Ils n'ont pas de défaut seulement + # une condition. + for k,v in self.definition.entites.items(): + if not dico.has_key(k): + if v.label == 'SIMP': + # Mot clé simple + dico[k]=v.defaut + elif v.label == 'FACT': + if v.statut in ('c','d') : + # Mot clé facteur avec défaut ou caché provisoire + dico[k]=v(val=None,nom=k,parent=self) + # On demande la suppression des pointeurs arrieres + # pour briser les eventuels cycles + dico[k].supprime() + else: + dico[k]=None + return dico - + def isBLOC(self): """ Indique si l'objet est un BLOC diff --git a/Noyau/N_MCCOMPO.py b/Noyau/N_MCCOMPO.py index 56fa972d..bb77a945 100644 --- a/Noyau/N_MCCOMPO.py +++ b/Noyau/N_MCCOMPO.py @@ -1,4 +1,4 @@ -#@ MODIF N_MCCOMPO Noyau DATE 03/09/2002 AUTEUR GNICOLAS G.NICOLAS +#@ MODIF N_MCCOMPO Noyau DATE 28/10/2003 AUTEUR DURAND C.DURAND # CONFIGURATION MANAGEMENT OF EDF VERSION # ====================================================================== # COPYRIGHT (C) 1991 - 2002 EDF R&D WWW.CODE-ASTER.ORG @@ -77,7 +77,7 @@ class MCCOMPO(N_OBJECT.OBJECT): # A ce stade, mc_liste ne contient que les fils de l'objet courant # args ne contient plus que des mots-clés qui n'ont pas été attribués car ils sont # à attribuer à des blocs du niveau inférieur ou bien sont des mots-clés erronés - dico_valeurs = self.cree_dict_valeurs(mc_liste) + dico_valeurs = self.cree_dict_condition(mc_liste,condition=1) for k,v in self.definition.entites.items(): if v.label != 'BLOC':continue # condition and a or b : Equivalent de l'expression : condition ? a : b du langage C @@ -91,7 +91,9 @@ class MCCOMPO(N_OBJECT.OBJECT): bloc = v(nom=k,val=args,parent=self) mc_liste.append(bloc) args=bloc.reste_val - dico_valeurs = self.cree_dict_valeurs(mc_liste) + # On ne recalcule pas le contexte car on ne tient pas compte des blocs + # pour évaluer les conditions de présence des blocs + #dico_valeurs = self.cree_dict_valeurs(mc_liste) # On conserve les arguments superflus dans l'attribut reste_val self.reste_val=args @@ -113,27 +115,27 @@ class MCCOMPO(N_OBJECT.OBJECT): else: return mc_liste - def cree_dict_valeurs(self,liste=[]): + def cree_dict_valeurs(self,liste=[],condition=0): """ - Cette méthode crée le contexte de l'objet courant sous la forme - d'un dictionnaire. - L'opération consiste à transformer une liste d'OBJECT en un - dictionnaire. - Ce dictionnaire servira de contexte pour évaluer les conditions des - blocs fils. + Cette méthode crée un contexte (sous la forme d'un dictionnaire) + à partir des valeurs des mots clés contenus dans l'argument liste. + L'opération consiste à parcourir la liste (d'OBJECT) et à la + transformer en un dictionnaire dont les clés sont les noms des + mots clés et les valeurs dépendent du type d'OBJECT. + Ce dictionnaire servira de liste d'arguments d'appel pour les + fonctions sd_prod de commandes et ops de macros ou de contexte + d'évaluation des conditions de présence de BLOC. + + Si l'argument condition de la méthode vaut 1, on ne + remonte pas les valeurs des mots clés contenus dans des blocs + pour eviter les bouclages. Cette méthode réalise les opérations suivantes en plus de transformer la liste en dictionnaire : - - ajouter tous les mots-clés non présents avec la valeur None - - - ajouter tous les mots-clés globaux (attribut position = 'global' - et 'global_jdc') - - ATTENTION : -- on ne remonte pas (semble en contradiction avec la - programmation de la méthode get_valeur du bloc) les - mots-clé fils d'un bloc au niveau du - contexte car celà peut générer des erreurs. + - ajouter tous les mots-clés non présents avec la valeur None + - ajouter tous les mots-clés globaux (attribut position = 'global' + et 'global_jdc') L'argument liste est, en général, une mc_liste en cours de construction, contenant les mots-clés locaux et les blocs déjà créés. @@ -141,57 +143,56 @@ class MCCOMPO(N_OBJECT.OBJECT): """ dico={} for v in liste: - k=v.nom - val = v.get_valeur() - # Si val est un dictionnaire, on inclut ses items dans le dictionnaire - # représentatif du contexte. Les blocs sont retournés par get_valeur - # sous la forme d'un dictionnaire : les mots-clés fils de blocs sont - # donc remontés au niveau du contexte. - if type(val)==types.DictionaryType: - for i,w in val.items(): - dico[i]=w + if v.isBLOC(): + # Si v est un BLOC, on inclut ses items dans le dictionnaire + # représentatif du contexte. Les blocs sont retournés par get_valeur + # sous la forme d'un dictionnaire : les mots-clés fils de blocs sont + # donc remontés au niveau du contexte. + if not condition:dico.update(v.get_valeur()) else: - dico[k]=val - # on rajoute tous les autres mots-clés locaux possibles avec la valeur + dico[v.nom]=v.get_valeur() + + # On rajoute tous les autres mots-clés locaux possibles avec la valeur # par défaut ou None - # Pour les mots-clés facteurs, on ne tient pas compte du défaut - # (toujours None) + # Pour les mots-clés facteurs, on ne traite que ceux avec statut défaut ('d') + # et caché ('c') + # On n'ajoute aucune information sur les blocs. Ils n'ont pas de défaut seulement + # une condition. for k,v in self.definition.entites.items(): if not dico.has_key(k): if v.label == 'SIMP': + # Mot clé simple dico[k]=v.defaut - # S il est declare global il n est pas necessaire de l ajouter - # aux mots cles globaux de l'etape - # car la methode recherche_mc_globaux les rajoutera - elif v.label == 'FACT' and v.statut in ('c','d') : - dico[k]=v(val=None,nom=k,parent=self) - # On demande la suppression des pointeurs arrieres - # pour briser les eventuels cycles - dico[k].supprime() - elif v.label != 'BLOC': - dico[k]=None + elif v.label == 'FACT' : + if v.statut in ('c','d') : + # Mot clé facteur avec défaut ou caché provisoire + dico[k]=v(val=None,nom=k,parent=self) + # On demande la suppression des pointeurs arrieres + # pour briser les eventuels cycles + dico[k].supprime() + else: + dico[k]=None # A ce stade on a rajouté tous les mots-clés locaux possibles (fils directs) avec leur # valeur par défaut ou la valeur None - # on rajoute les mots-clés globaux ... + + # On rajoute les mots-clés globaux sans écraser les clés existantes dico_mc = self.recherche_mc_globaux() - for nom,mc in dico_mc.items() : - if not dico.has_key(nom) : dico[nom]=mc.valeur - # Il nous reste à évaluer la présence des blocs en fonction du contexte qui a changé - for k,v in self.definition.entites.items(): - if v.label != 'BLOC' : continue - # condition and a or b : Equivalent de l'expression : condition ? a : b du langage C - globs= self.jdc and self.jdc.condition_context or {} - if v.verif_presence(dico,globs): - # le bloc k doit etre présent : on crée temporairement l'objet MCBLOC correspondant - # on lui passe un parent égal à None pour qu'il ne soit pas enregistré - bloc = v(nom=k,val=None,parent=None) - dico_bloc = bloc.cree_dict_valeurs() - bloc.supprime() - # on va updater dico avec dico_bloc en veillant à ne pas écraser - # des valeurs déjà présentes - for cle in dico_bloc.keys(): - if not dico.has_key(cle): - dico[cle]=dico_bloc[cle] + dico_mc.update(dico) + dico=dico_mc + + return dico + + def cree_dict_condition(self,liste=[],condition=0): + """ + Methode pour construire un contexte qui servira dans l'évaluation + des conditions de présence de blocs. Si une commande a un concept + produit réutilisé, on ajoute la clé 'reuse' + """ + dico=self.cree_dict_valeurs(liste,condition=1) + # On ajoute la cle "reuse" pour les MCCOMPO qui ont un attribut reuse. A destination + # uniquement des commandes. Ne devrait pas etre dans cette classe mais dans une classe dérivée + if not dico.has_key('reuse') and hasattr(self,'reuse'): + dico['reuse']=self.reuse return dico def recherche_mc_globaux(self): @@ -292,9 +293,13 @@ class MCCOMPO(N_OBJECT.OBJECT): for v in self.mc_liste: if v.nom == name : return v if restreint == 'non' : - for k,v in self.definition.entites.items(): - if k == name: - if v.valeur != None : return v(None,k,None) + try: + entite=self.definition.entites[name] + if entite.label == 'SIMP' or (entite.label == 'FACT' and entite.statut in ( 'c', 'd')): + return entite(None,name,None) + except: + pass + return None def append_mc_global(self,mc): diff --git a/Noyau/N_MCLIST.py b/Noyau/N_MCLIST.py index 9b21cdf9..49736eb1 100644 --- a/Noyau/N_MCLIST.py +++ b/Noyau/N_MCLIST.py @@ -144,3 +144,14 @@ class MCList(UserList.UserList): self.etape=parent.etape for mcfact in self.data: mcfact.reparent(parent) + + def get_etape(self): + """ + Retourne l'étape à laquelle appartient self + Un objet de la catégorie etape doit retourner self pour indiquer que + l'étape a été trouvée + XXX double emploi avec self.etape ??? + """ + if self.parent == None: return None + return self.parent.get_etape() + diff --git a/Noyau/N_MCSIMP.py b/Noyau/N_MCSIMP.py index 7df9f9fd..5e123bd1 100644 --- a/Noyau/N_MCSIMP.py +++ b/Noyau/N_MCSIMP.py @@ -99,39 +99,39 @@ class MCSIMP(N_OBJECT.OBJECT): visitor.visitMCSIMP(self) def copy(self): - """ Retourne une copie de self """ - objet = self.makeobjet() - # il faut copier les listes et les tuples mais pas les autres valeurs - # possibles (réel,SD,...) - if type(self.valeur) in (types.ListType,types.TupleType): - objet.valeur = copy(self.valeur) - else: - objet.valeur = self.valeur - objet.val = objet.valeur - return objet + """ Retourne une copie de self """ + objet = self.makeobjet() + # il faut copier les listes et les tuples mais pas les autres valeurs + # possibles (réel,SD,...) + if type(self.valeur) in (types.ListType,types.TupleType): + objet.valeur = copy(self.valeur) + else: + objet.valeur = self.valeur + objet.val = objet.valeur + return objet def makeobjet(self): - return self.definition(val = None, nom = self.nom,parent = self.parent) + return self.definition(val = None, nom = self.nom,parent = self.parent) def reparent(self,parent): - """ + """ Cette methode sert a reinitialiser la parente de l'objet - """ - self.parent=parent - self.jdc=parent.jdc - self.etape=parent.etape + """ + self.parent=parent + self.jdc=parent.jdc + self.etape=parent.etape def get_sd_utilisees(self): - """ - Retourne une liste qui contient la SD utilisée par self si c'est le cas - ou alors une liste vide - """ - l=[] - if type(self.valeur) == types.InstanceType: - #XXX Est ce différent de isinstance(self.valeur,ASSD) ?? - if issubclass(self.valeur.__class__,ASSD) : l.append(self.valeur) - elif type(self.valeur) in (types.TupleType,types.ListType): - for val in self.valeur : - if type(val) == types.InstanceType: - if issubclass(val.__class__,ASSD) : l.append(val) - return l + """ + Retourne une liste qui contient la SD utilisée par self si c'est le cas + ou alors une liste vide + """ + l=[] + if type(self.valeur) == types.InstanceType: + #XXX Est ce différent de isinstance(self.valeur,ASSD) ?? + if issubclass(self.valeur.__class__,ASSD) : l.append(self.valeur) + elif type(self.valeur) in (types.TupleType,types.ListType): + for val in self.valeur : + if type(val) == types.InstanceType: + if issubclass(val.__class__,ASSD) : l.append(val) + return l diff --git a/Noyau/N_OBJECT.py b/Noyau/N_OBJECT.py index 48712790..52abd6cd 100644 --- a/Noyau/N_OBJECT.py +++ b/Noyau/N_OBJECT.py @@ -89,3 +89,10 @@ class OBJECT: else: return val + def reparent(self,parent): + """ + Cette methode sert a reinitialiser la parente de l'objet + """ + self.parent=parent + self.jdc=parent.jdc + diff --git a/Noyau/N_VALIDATOR.py b/Noyau/N_VALIDATOR.py index 1fcbe331..6db3a475 100644 --- a/Noyau/N_VALIDATOR.py +++ b/Noyau/N_VALIDATOR.py @@ -29,8 +29,8 @@ class Valid: """ Cette classe est la classe mere des validateurs Accas Elle doit etre derivee - Elle ne presente que la signature des methodes - indispensables pour son bon fonctionnement + Elle presente la signature des methodes indispensables pour son bon + fonctionnement et dans certains cas leur comportement par défaut. @ivar cata_info: raison de la validite ou de l'invalidite du validateur meme @type cata_info: C{string} @@ -43,8 +43,42 @@ class Valid: raise "Must be implemented" def info(self): + """ + Cette methode retourne une chaine de caractères informative sur + la validation demandée par le validateur. Elle est utilisée + pour produire le compte-rendu de validité du mot clé associé. + """ return "valeur valide" + def aide(self): + """ + Cette methode retourne une chaine de caractère qui permet + de construire un message d'aide en ligne. + En général, le message retourné est le meme que celui retourné par la + méthode info. + """ + return self.info() + + def info_erreur_item(self): + """ + Cette méthode permet d'avoir un message d'erreur pour un item + dans une liste dans le cas ou le validateur fait des vérifications + sur les items d'une liste. Si le validateur fait seulement des + vérifications sur la liste elle meme et non sur ses items, la méthode + doit retourner une chaine vide. + """ + return " " + + def info_erreur_liste(self): + """ + Cette méthode a un comportement complémentaire de celui de + info_erreur_item. Elle retourne un message d'erreur lié uniquement + aux vérifications sur la liste elle meme et pas sur ses items. + Dans le cas où le validateur ne fait pas de vérification sur des + listes, elle retourne une chaine vide + """ + return " " + def verif(self,valeur): """ Cette methode sert a verifier si la valeur passee en argument est consideree @@ -58,9 +92,29 @@ class Valid: """ raise "Must be implemented" - def error(self,valeur): + def verif_item(self,valeur): + """ + La methode verif du validateur effectue une validation complete de + la valeur. valeur peut etre un scalaire ou une liste. Le validateur + doit traiter les 2 aspects s'il accepte des listes (dans ce cas la + methode is_list doit retourner 1). + La methode valid_item sert pour effectuer des validations partielles + de liste. Elle doit uniquement verifier la validite d'un item de + liste mais pas les caracteristiques de la liste. + """ return 0 + def valide_liste_partielle(self,liste_courante): + """ + Cette methode retourne un entier qui indique si liste_courante est partiellement valide (valeur 1) + ou invalide (valeur 0). La validation partielle concerne les listes en cours de construction : on + veut savoir si la liste en construction peut etre complétée ou si elle peut déjà etre considérée + comme invalide. + En général un validateur effectue la meme validation pour les listes partielles et les + listes complètes. + """ + return self.verif(liste_courante) + def verif_cata(self): """ Cette methode sert a realiser des verifications du validateur lui meme. @@ -74,7 +128,115 @@ class Valid: """ return 1 -class RangeVal(Valid): + def is_list(self): + """ + Cette méthode retourne un entier qui indique si le validateur + permet les listes (valeur 1) ou ne les permet pas (valeur 0). + Par défaut, un validateur n'autorise que des scalaires. + """ + return 0 + + def has_into(self): + """ + Cette méthode retourne un entier qui indique si le validateur + propose une liste de choix (valeur 1) ou n'en propose pas. + Par défaut, un validateur n'en propose pas. + """ + return 0 + + def get_into(self,liste_courante=None,into_courant=None): + """ + Cette méthode retourne la liste de choix proposée par le validateur. + Si le validateur ne propose pas de liste de choix, la méthode + retourne None. + L'argument d'entrée liste_courante, s'il est différent de None, donne + la liste des choix déjà effectués par l'utilisateur. Dans ce cas, la + méthode get_into doit calculer la liste des choix en en tenant + compte. Par exemple, si le validateur n'autorise pas les répétitions, + la liste des choix retournée ne doit pas contenir les choix déjà + contenus dans liste_courante. + L'argument d'entrée into_courant, s'il est différent de None, donne + la liste des choix proposés par d'autres validateurs. Dans ce cas, + la méthode get_into doit calculer la liste des choix à retourner + en se limitant à cette liste initiale. Par exemple, si into_courant + vaut (1,2,3) et que le validateur propose la liste de choix (3,4,5), + la méthode ne doit retourner que (3,). + + La méthode get_into peut retourner une liste vide [], ce qui veut + dire qu'il n'y a pas (ou plus) de choix possible. Cette situation + peut etre normale : l''utilisateur a utilisé tous les choix, ou + résulter d'une incohérence des validateurs : + choix parmi (1,2,3) ET choix parmi (4,5,6). Il est impossible de + faire la différence entre ces deux situations. + """ + return into_courant + + def is_eval(self,valeur): + """ + Cette méthode indique si valeur est un objet de type EVAL ou autre + que l'on ne cherchera pas à evaluer et qui doit etre considere + comme toujours valide. Si c'est un objet de ce type elle retourne + la valeur 1 sinon la valeur 0 + """ + return type(valeur) == types.InstanceType and valeur.__class__.__name__ in ('EVAL', + 'entier','reel','chaine', 'complexe','liste','PARAMETRE_EVAL') + + def is_param(self,valeur): + """ + Cette méthode indique si valeur est un objet de type PARAMETRE + dont on cherchera à evaluer la valeur (valeur.valeur) + """ + return type(valeur) == types.InstanceType and valeur.__class__.__name__ in ('PARAMETRE',) + + def is_unknown(self,valeur): + """ + Cette méthode indique si valeur est un objet de type inconnu + c'est à dire ni de type EVAL ni de type PARAMETRE + """ + return type(valeur) == types.InstanceType and valeur.__class__.__name__ not in ('EVAL', + 'entier','reel','chaine', 'complexe','liste','PARAMETRE_EVAL','PARAMETRE') + +class ListVal(Valid): + """ + Cette classe sert de classe mère pour tous les validateurs qui acceptent + des listes. + """ + def is_list(self): + return 1 + + def get_into(self,liste_courante=None,into_courant=None): + """ + Cette méthode get_into effectue un traitement général qui consiste + a filtrer la liste de choix into_courant, si elle existe, en ne + conservant que les valeurs valides (appel de la méthode valid). + """ + if into_courant is None: + return None + else: + liste_choix=[] + for e in into_courant: + if self.verif(e): + liste_choix.append(e) + return liste_choix + + def verif(self,valeur): + """ + Méthode verif pour les validateurs de listes. Cette méthode + fait appel à la méthode verif_item sur chaque élément de la + liste. Si valeur est un paramètre, on utilise sa valeur effective + valeur.valeur. + """ + if self.is_param(valeur): + valeur=valeur.valeur + if type(valeur) in (types.ListType,types.TupleType): + for val in valeur: + if not self.verif_item(val): + return 0 + return 1 + else: + return self.verif_item(valeur) + +class RangeVal(ListVal): """ Exemple de classe validateur : verification qu'une valeur est dans un intervalle. @@ -91,16 +253,12 @@ class RangeVal(Valid): def info(self): return "valeur dans l'intervalle %s , %s" %(self.low,self.high) - def verif(self,valeur): - if type(valeur) in (types.ListType,types.TupleType): - for val in valeur: - if val < self.low :return 0 - if val > self.high:return 0 - return 1 - else: - if valeur < self.low :return 0 - if valeur > self.high:return 0 - return 1 + def verif_item(self,valeur): + return valeur > self.low and valeur < self.high + + def info_erreur_item(self) : + return "La valeur doit être comprise entre %s et %s" % (self.low, + self.high) def verif_cata(self): if self.low > self.high : return 0 @@ -120,7 +278,28 @@ class CardVal(Valid): self.cata_info="%s doit etre inferieur a %s" % (min,max) def info(self): - return "longueur comprise entre %s et %s" % (self.min,self.max) + return "longueur de liste comprise entre %s et %s" % (self.min,self.max) + + def info_erreur_liste(self): + return "La cardinalité de la liste doit être comprise entre %s et %s" % (self.min,self.max) + + def is_list(self): + return self.max == '**' or self.max > 1 + + def get_into(self,liste_courante=None,into_courant=None): + if into_courant is None: + return None + elif liste_courante is None: + return into_courant + elif self.max == '**': + return into_courant + elif len(liste_courante) < self.max: + return into_courant + else: + return [] + + def verif_item(self,valeur): + return 1 def verif(self,valeur): if type(valeur) in (types.ListType,types.TupleType): @@ -136,7 +315,14 @@ class CardVal(Valid): if self.min != '**' and self.max != '**' and self.min > self.max : return 0 return 1 -class PairVal(Valid): + def valide_liste_partielle(self,liste_courante=None): + validite=1 + if liste_courante != None : + if len(liste_courante) > self.max : + validite=0 + return validite + +class PairVal(ListVal): """ Exemple de classe validateur : verification qu'une valeur est paire. @@ -149,6 +335,19 @@ class PairVal(Valid): def info(self): return "valeur paire" + def info_erreur_item(self): + return "La valeur saisie doit être paire" + + def verif_item(self,valeur): + if type(valeur) == types.InstanceType: + if self.is_eval(valeur): + return 1 + elif self.is_param(valeur): + valeur=valeur.valeur + else: + return 0 + return valeur % 2 == 0 + def verif(self,valeur): if type(valeur) in (types.ListType,types.TupleType): for val in valeur: @@ -158,7 +357,7 @@ class PairVal(Valid): if valeur % 2 != 0:return 0 return 1 -class EnumVal(Valid): +class EnumVal(ListVal): """ Exemple de classe validateur : verification qu'une valeur est prise dans une liste de valeurs. @@ -172,16 +371,27 @@ class EnumVal(Valid): def info(self): return "valeur dans %s" % `self.into` - def verif(self,valeur): - if type(valeur) in (types.ListType,types.TupleType): - for val in valeur: - if val not in self.into:return 0 - return 1 + def verif_item(self,valeur): + if valeur not in self.into:return 0 + return 1 + + def has_into(self): + return 1 + + def get_into(self,liste_courante=None,into_courant=None): + if into_courant is None: + liste_choix= list(self.into) else: - if valeur not in self.into:return 0 - return 1 + liste_choix=[] + for e in into_courant: + if e in self.into: + liste_choix.append(e) + return liste_choix + + def info_erreur_item(self): + return "La valeur n'est pas dans la liste des choix possibles" -class NoRepeat(Valid): +class NoRepeat(ListVal): """ Verification d'absence de doublons dans la liste. """ @@ -189,7 +399,13 @@ class NoRepeat(Valid): self.cata_info="" def info(self): - return ": présence de doublon dans la liste" + return ": pas de présence de doublon dans la liste" + + def info_erreur_liste(self): + return "Les doublons ne sont pas permis" + + def verif_item(self,valeur): + return 1 def verif(self,valeur): if type(valeur) in (types.ListType,types.TupleType): @@ -200,7 +416,23 @@ class NoRepeat(Valid): else: return 1 -class LongStr(Valid): + def get_into(self,liste_courante=None,into_courant=None): + """ + Methode get_into spécifique pour validateur NoRepeat, on retourne + une liste de choix qui ne contient aucune valeur de into_courant + déjà contenue dans liste_courante + """ + if into_courant is None: + liste_choix=None + else: + liste_choix=[] + for e in into_courant: + if e in liste_choix: continue + if liste_courante is not None and e in liste_courante: continue + liste_choix.append(e) + return liste_choix + +class LongStr(ListVal): """ Verification de la longueur d une chaine """ @@ -212,18 +444,20 @@ class LongStr(Valid): def info(self): return "longueur de la chaine entre %s et %s" %(self.low,self.high) - def verif(self,valeur): - if type(valeur) in (types.ListType,types.TupleType): - for val in valeur: - if len(val) < self.low :return 0 - if len(val) > self.high:return 0 - return 1 - else: - if len(valeur) < self.low :return 0 - if len(valeur) > self.high:return 0 - return 1 + def info_erreur_item(self): + return "Longueur de la chaine incorrecte" + + def verif_item(self,valeur): + low=self.low + high=self.high + if valeur[0]=="'" and valeur[-1]=="'" : + low=low+2 + high=high+2 + if len(valeur) < low :return 0 + if len(valeur) > high:return 0 + return 1 -class OrdList(Valid): +class OrdList(ListVal): """ Verification qu'une liste est croissante ou decroissante """ @@ -234,6 +468,9 @@ class OrdList(Valid): def info(self): return "liste %s" % self.ord + def info_erreur_liste(self) : + return "La liste doit être en ordre "+self.ord + def verif(self,valeur): if type(valeur) in (types.ListType,types.TupleType): if self.ord=='croissant': @@ -251,6 +488,28 @@ class OrdList(Valid): else: return 1 + def verif_item(self,valeur): + return 1 + + def get_into(self,liste_courante=None,into_courant=None): + """ + Methode get_into spécifique pour validateur OrdList, on retourne + une liste de choix qui ne contient aucune valeur de into_courant + dont la valeur est inférieure à la dernière valeur de + liste_courante, si elle est différente de None. + """ + if into_courant is None: + return None + elif not liste_courante : + return into_courant + else: + liste_choix=[] + last_val=liste_choix[-1] + for e in into_courant: + if self.ord=='croissant' and e <= last_val:continue + if self.ord=='decroissant' and e >= last_val:continue + liste_choix.append(e) + return liste_choix CoercableFuncs = { types.IntType: int, types.LongType: long, @@ -258,7 +517,7 @@ CoercableFuncs = { types.IntType: int, types.ComplexType: complex, types.UnicodeType: unicode } -class TypeVal(Valid): +class TypeVal(ListVal): """ Cette classe est un validateur qui controle qu'une valeur est bien du type Python attendu. @@ -281,22 +540,14 @@ class TypeVal(Valid): return value raise ValError - def verif(self,valeur): - if type(valeur) in (types.ListType,types.TupleType): - for val in valeur: - try: - self.coerce(val) - except: - return 0 - return 1 - else: - try: - self.coerce(valeur) - except: - return 0 - return 1 + def verif_item(self,valeur): + try: + self.coerce(valeur) + except: + return 0 + return 1 -class InstanceVal(Valid): +class InstanceVal(ListVal): """ Cette classe est un validateur qui controle qu'une valeur est bien une instance (au sens Python) d'une classe @@ -310,11 +561,7 @@ class InstanceVal(Valid): def info(self): return "valeur d'instance de %s" % self.aClass.__name__ - def verif(self,valeur): - if type(valeur) in (types.ListType,types.TupleType): - for val in valeur: - if not isinstance(val,self.aClass): return 0 - return 1 + def verif_item(self,valeur): if not isinstance(valeur,self.aClass): return 0 return 1 @@ -375,10 +622,11 @@ class FunctionVal(Valid): class OrVal(Valid): """ Cette classe est un validateur qui controle une liste de validateurs - Elle verifie qu'au moins un des validateurs de la liste a valide la valeur + Elle verifie qu'au moins un des validateurs de la liste valide la valeur """ def __init__(self,validators=()): - if type(validators) not in (types.ListType,types.TupleType): validators=(validators,) + if type(validators) not in (types.ListType,types.TupleType): + validators=(validators,) self.validators=[] for validator in validators: if type(validator) == types.FunctionType: @@ -390,6 +638,34 @@ class OrVal(Valid): def info(self): return "\n ou ".join([v.info() for v in self.validators]) + def info_erreur_item(self): + l=[] + for v in self.validators: + err=v.info_erreur_item() + if err != " " : l.append(err) + chaine=" \n ou ".join(l) + return chaine + + def info_erreur_liste(self): + l=[] + for v in self.validators: + err=v.info_erreur_liste() + if err != " " : l.append(err) + chaine=" \n ou ".join(l) + return chaine + + def is_list(self): + """ + Si plusieurs validateurs sont reliés par un OU + il suffit qu'un seul des validateurs attende une liste + pour qu'on considère que leur union attend une liste. + """ + for validator in self.validators: + v=validator.is_list() + if v : + return 1 + return 0 + def verif(self,valeur): for validator in self.validators: v=validator.verif(valeur) @@ -397,6 +673,13 @@ class OrVal(Valid): return 1 return 0 + def verif_item(self,valeur): + for validator in self.validators: + v=validator.verif_item(valeur) + if v : + return 1 + return 0 + def verif_cata(self): infos=[] for validator in self.validators: @@ -408,13 +691,58 @@ class OrVal(Valid): self.cata_info="" return 1 + def has_into(self): + """ + Dans le cas ou plusieurs validateurs sont reliés par un OU + il faut que tous les validateurs proposent un choix pour + qu'on considère que leur union propose un choix. + Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix + En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un choix (1,2,3,4,5,6) + """ + for validator in self.validators: + v=validator.has_into() + if not v : + return 0 + return 1 + + def get_into(self,liste_courante=None,into_courant=None): + """ + Dans le cas ou plusieurs validateurs sont reliés par un OU + tous les validateurs doivent proposer un choix pour + qu'on considère que leur union propose un choix. Tous les choix + proposés par les validateurs sont réunis (opérateur d'union). + Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix + En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un + choix (1,2,3,4,5,6) + """ + validator_into=[] + for validator in self.validators: + v_into=validator.get_into(liste_courante,into_courant) + if v_into is None: + return v_into + validator_into.extend(v_into) + return validator_into + + def valide_liste_partielle(self,liste_courante=None): + """ + Méthode de validation de liste partielle pour le validateur Or. + Si un des validateurs gérés par le validateur Or considère la + liste comme valide, le validateur Or la considère comme valide. + """ + for validator in self.validators: + v=validator.valide_liste_partielle(liste_courante) + if v : + return 1 + return 0 + class AndVal(Valid): """ Cette classe est un validateur qui controle une liste de validateurs - Elle verifie que tous les validateurs de la liste sont positifs + Elle verifie que tous les validateurs de la liste valident la valeur """ def __init__(self,validators=()): - if type(validators) not in (types.ListType,types.TupleType): validators=(validators,) + if type(validators) not in (types.ListType,types.TupleType): + validators=(validators,) self.validators=[] for validator in validators: if type(validator) == types.FunctionType: @@ -424,7 +752,30 @@ class AndVal(Valid): self.cata_info="" def info(self): - return " et ".join([v.info() for v in self.validators]) + return "\n et ".join([v.info() for v in self.validators]) + + def info_erreur_item(self): + chaine="" + a=1 + for v in self.validators: + if v.info_erreur_item() != " " : + if a==1: + chaine=v.info_erreur_item() + a=0 + else: + chaine=chaine+" \n et "+v.info_erreur_item() + return chaine + + def info_erreur_liste(self): + a=1 + for v in self.validators: + if v.info_erreur_liste() != " " : + if a==1: + chaine=v.info_erreur_liste() + a=0 + else: + chaine=chaine+" \n et "+v.info_erreur_liste() + return chaine def verif(self,valeur): for validator in self.validators: @@ -434,6 +785,15 @@ class AndVal(Valid): return 0 return 1 + def verif_item(self,valeur): + for validator in self.validators: + v=validator.verif_item(valeur) + if not v : + # L'info n'est probablement pas la meme que pour verif ??? + self.local_info=validator.info() + return 0 + return 1 + def verif_cata(self): infos=[] for validator in self.validators: @@ -445,6 +805,62 @@ class AndVal(Valid): self.cata_info="" return 1 + def valide_liste_partielle(self,liste_courante=None): + """ + Méthode de validation de liste partielle pour le validateur And. + Tous les validateurs gérés par le validateur And doivent considérer + la liste comme valide, pour que le validateur And la considère + comme valide. + """ + for validator in self.validators: + v=validator.valide_liste_partielle(liste_courante) + if not v : + return 0 + return 1 + + def is_list(self): + """ + Si plusieurs validateurs sont reliés par un ET + il faut que tous les validateurs attendent une liste + pour qu'on considère que leur intersection attende une liste. + Exemple Range(2,5) ET Card(1) n'attend pas une liste + Range(2,5) ET Pair attend une liste + """ + for validator in self.validators: + v=validator.is_list() + if v == 0 : + return 0 + return 1 + + def has_into(self): + """ + Dans le cas ou plusieurs validateurs sont reliés par un ET + il suffit qu'un seul validateur propose un choix pour + qu'on considère que leur intersection propose un choix. + Exemple : Enum(1,2,3) ET entier pair, propose un choix + En revanche, entier pair ET superieur à 10 ne propose pas de choix + """ + for validator in self.validators: + v=validator.has_into() + if v : + return 1 + return 0 + + def get_into(self,liste_courante=None,into_courant=None): + """ + Dans le cas ou plusieurs validateurs sont reliés par un ET + il suffit qu'un seul validateur propose un choix pour + qu'on considère que leur intersection propose un choix. Tous les + choix proposés par les validateurs sont croisés (opérateur + d'intersection) + Exemple : Enum(1,2,3) ET entier pair, propose un choix (2,) + En revanche, Enum(1,2,3) ET Enum(4,5,6) ne propose pas de choix. + """ + for validator in self.validators: + into_courant=validator.get_into(liste_courante,into_courant) + if into_courant in ([],None):break + return into_courant + def do_liste(validators): """ Convertit une arborescence de validateurs en OrVal ou AndVal