Salome HOME
correction pour acception de concept liste
[tools/eficas.git] / Noyau / N_VALIDATOR.py
index 1fcbe331df9fefc0e41c7891f83be1f191b997ca..64d1fbac6e38c540d5170d7315ac2674baf9d500 100644 (file)
@@ -1,4 +1,5 @@
-#@ MODIF N_VALIDATOR Noyau  DATE 09/09/2003   AUTEUR DURAND C.DURAND 
+#@ MODIF N_VALIDATOR Noyau  DATE 20/09/2004   AUTEUR DURAND C.DURAND 
+# -*- coding: iso-8859-1 -*-
 #            CONFIGURATION MANAGEMENT OF EDF VERSION
 # ======================================================================
 # COPYRIGHT (C) 1991 - 2003  EDF R&D                  WWW.CODE-ASTER.ORG
@@ -16,6 +17,7 @@
 # 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 toutes les classes necessaires pour
    implanter le concept de validateur dans Accas
@@ -29,8 +31,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 +45,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 +94,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 +130,105 @@ 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_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 pas de type PARAMETRE
+       """
+       return type(valeur) == types.InstanceType and valeur.__class__.__name__ not in (
+                    '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 +245,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 etre comprise entre %s et %s" % (self.low,
+                                                                  self.high)
 
       def verif_cata(self):
           if self.low > self.high : return 0
@@ -120,7 +270,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 "Le cardinal de la liste doit etre compris 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 +307,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 +327,17 @@ class PairVal(Valid):
       def info(self):
           return "valeur paire"
 
+      def info_erreur_item(self):
+          return "La valeur saisie doit etre paire"
+
+      def verif_item(self,valeur):
+          if type(valeur) == types.InstanceType:
+             if 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 +347,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 +361,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
 
-class NoRepeat(Valid):
+      def info_erreur_item(self):
+          return "La valeur n'est pas dans la liste des choix possibles"
+
+class NoRepeat(ListVal):
       """
           Verification d'absence de doublons dans la liste.
       """
@@ -189,7 +389,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 +406,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 +434,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 +458,9 @@ class OrdList(Valid):
       def info(self):
           return "liste %s" % self.ord
 
+      def info_erreur_liste(self) :
+          return "La liste doit etre en ordre "+self.ord
+
       def verif(self,valeur):
           if type(valeur) in (types.ListType,types.TupleType):
              if self.ord=='croissant':
@@ -251,6 +478,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 +507,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 +530,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 +551,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 +612,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 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 +628,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 +663,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 +681,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 +742,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 +775,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 +795,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