1 #@ MODIF N_VALIDATOR Noyau DATE 09/09/2003 AUTEUR DURAND C.DURAND
2 # CONFIGURATION MANAGEMENT OF EDF VERSION
3 # ======================================================================
4 # COPYRIGHT (C) 1991 - 2003 EDF R&D WWW.CODE-ASTER.ORG
5 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
6 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
7 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
8 # (AT YOUR OPTION) ANY LATER VERSION.
10 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
11 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
12 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
13 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
15 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
16 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
17 # 1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
18 # ======================================================================
20 Ce module contient toutes les classes necessaires pour
21 implanter le concept de validateur dans Accas
23 import types,exceptions
25 class ValError ( exceptions.Exception ):
30 Cette classe est la classe mere des validateurs Accas
31 Elle doit etre derivee
32 Elle presente la signature des methodes indispensables pour son bon
33 fonctionnement et dans certains cas leur comportement par défaut.
35 @ivar cata_info: raison de la validite ou de l'invalidite du validateur meme
36 @type cata_info: C{string}
38 def __init__(self,*tup,**args):
40 Cette methode sert a initialiser les attributs du validateur
43 raise "Must be implemented"
47 Cette methode retourne une chaine de caractères informative sur
48 la validation demandée par le validateur. Elle est utilisée
49 pour produire le compte-rendu de validité du mot clé associé.
51 return "valeur valide"
55 Cette methode retourne une chaine de caractère qui permet
56 de construire un message d'aide en ligne.
57 En général, le message retourné est le meme que celui retourné par la
62 def info_erreur_item(self):
64 Cette méthode permet d'avoir un message d'erreur pour un item
65 dans une liste dans le cas ou le validateur fait des vérifications
66 sur les items d'une liste. Si le validateur fait seulement des
67 vérifications sur la liste elle meme et non sur ses items, la méthode
68 doit retourner une chaine vide.
72 def info_erreur_liste(self):
74 Cette méthode a un comportement complémentaire de celui de
75 info_erreur_item. Elle retourne un message d'erreur lié uniquement
76 aux vérifications sur la liste elle meme et pas sur ses items.
77 Dans le cas où le validateur ne fait pas de vérification sur des
78 listes, elle retourne une chaine vide
82 def verif(self,valeur):
84 Cette methode sert a verifier si la valeur passee en argument est consideree
85 comme valide ou non par le validateur. Dans le premier cas le validateur retourne 1
86 (valide) sinon 0 (invalide).
88 @type valeur: tout type python
89 @param valeur: valeur du mot cle a valider
91 @return: indicateur de validite 1 (valide) ou 0 (invalide)
93 raise "Must be implemented"
95 def verif_item(self,valeur):
97 La methode verif du validateur effectue une validation complete de
98 la valeur. valeur peut etre un scalaire ou une liste. Le validateur
99 doit traiter les 2 aspects s'il accepte des listes (dans ce cas la
100 methode is_list doit retourner 1).
101 La methode valid_item sert pour effectuer des validations partielles
102 de liste. Elle doit uniquement verifier la validite d'un item de
103 liste mais pas les caracteristiques de la liste.
107 def valide_liste_partielle(self,liste_courante):
109 Cette methode retourne un entier qui indique si liste_courante est partiellement valide (valeur 1)
110 ou invalide (valeur 0). La validation partielle concerne les listes en cours de construction : on
111 veut savoir si la liste en construction peut etre complétée ou si elle peut déjà etre considérée
113 En général un validateur effectue la meme validation pour les listes partielles et les
116 return self.verif(liste_courante)
118 def verif_cata(self):
120 Cette methode sert a realiser des verifications du validateur lui meme.
121 Elle est facultative et retourne 1 (valide) par defaut.
122 Elle retourne 0 si le validateur est lui meme invalide si par exemple ses
123 parametres de definition ne sont pas corrects.
124 La raison de l'invalidite est stockee dans l'attribut cata_info.
127 @return: indicateur de validite 1 (valide) ou 0 (invalide)
133 Cette méthode retourne un entier qui indique si le validateur
134 permet les listes (valeur 1) ou ne les permet pas (valeur 0).
135 Par défaut, un validateur n'autorise que des scalaires.
141 Cette méthode retourne un entier qui indique si le validateur
142 propose une liste de choix (valeur 1) ou n'en propose pas.
143 Par défaut, un validateur n'en propose pas.
147 def get_into(self,liste_courante=None,into_courant=None):
149 Cette méthode retourne la liste de choix proposée par le validateur.
150 Si le validateur ne propose pas de liste de choix, la méthode
152 L'argument d'entrée liste_courante, s'il est différent de None, donne
153 la liste des choix déjà effectués par l'utilisateur. Dans ce cas, la
154 méthode get_into doit calculer la liste des choix en en tenant
155 compte. Par exemple, si le validateur n'autorise pas les répétitions,
156 la liste des choix retournée ne doit pas contenir les choix déjà
157 contenus dans liste_courante.
158 L'argument d'entrée into_courant, s'il est différent de None, donne
159 la liste des choix proposés par d'autres validateurs. Dans ce cas,
160 la méthode get_into doit calculer la liste des choix à retourner
161 en se limitant à cette liste initiale. Par exemple, si into_courant
162 vaut (1,2,3) et que le validateur propose la liste de choix (3,4,5),
163 la méthode ne doit retourner que (3,).
165 La méthode get_into peut retourner une liste vide [], ce qui veut
166 dire qu'il n'y a pas (ou plus) de choix possible. Cette situation
167 peut etre normale : l''utilisateur a utilisé tous les choix, ou
168 résulter d'une incohérence des validateurs :
169 choix parmi (1,2,3) ET choix parmi (4,5,6). Il est impossible de
170 faire la différence entre ces deux situations.
174 def is_eval(self,valeur):
176 Cette méthode indique si valeur est un objet de type EVAL ou autre
177 que l'on ne cherchera pas à evaluer et qui doit etre considere
178 comme toujours valide. Si c'est un objet de ce type elle retourne
179 la valeur 1 sinon la valeur 0
181 return type(valeur) == types.InstanceType and valeur.__class__.__name__ in ('EVAL',
182 'entier','reel','chaine', 'complexe','liste','PARAMETRE_EVAL')
184 def is_param(self,valeur):
186 Cette méthode indique si valeur est un objet de type PARAMETRE
187 dont on cherchera à evaluer la valeur (valeur.valeur)
189 return type(valeur) == types.InstanceType and valeur.__class__.__name__ in ('PARAMETRE',)
191 def is_unknown(self,valeur):
193 Cette méthode indique si valeur est un objet de type inconnu
194 c'est à dire ni de type EVAL ni de type PARAMETRE
196 return type(valeur) == types.InstanceType and valeur.__class__.__name__ not in ('EVAL',
197 'entier','reel','chaine', 'complexe','liste','PARAMETRE_EVAL','PARAMETRE')
199 class ListVal(Valid):
201 Cette classe sert de classe mère pour tous les validateurs qui acceptent
207 def get_into(self,liste_courante=None,into_courant=None):
209 Cette méthode get_into effectue un traitement général qui consiste
210 a filtrer la liste de choix into_courant, si elle existe, en ne
211 conservant que les valeurs valides (appel de la méthode valid).
213 if into_courant is None:
217 for e in into_courant:
219 liste_choix.append(e)
222 def verif(self,valeur):
224 Méthode verif pour les validateurs de listes. Cette méthode
225 fait appel à la méthode verif_item sur chaque élément de la
226 liste. Si valeur est un paramètre, on utilise sa valeur effective
229 if self.is_param(valeur):
231 if type(valeur) in (types.ListType,types.TupleType):
233 if not self.verif_item(val):
237 return self.verif_item(valeur)
239 class RangeVal(ListVal):
241 Exemple de classe validateur : verification qu'une valeur
242 est dans un intervalle.
243 Pour une liste on verifie que tous les elements sont
245 Susceptible de remplacer les attributs "vale_min" "vale_max"
248 def __init__(self,low,high):
251 self.cata_info="%s doit etre inferieur a %s" %(low,high)
254 return "valeur dans l'intervalle %s , %s" %(self.low,self.high)
256 def verif_item(self,valeur):
257 return valeur > self.low and valeur < self.high
259 def info_erreur_item(self) :
260 return "La valeur doit être comprise entre %s et %s" % (self.low,
263 def verif_cata(self):
264 if self.low > self.high : return 0
267 class CardVal(Valid):
269 Exemple de classe validateur : verification qu'une liste est
270 d'une longueur superieur a un minimum (min) et inferieure
272 Susceptible de remplacer les attributs "min" "max" dans les
275 def __init__(self,min='**',max='**'):
278 self.cata_info="%s doit etre inferieur a %s" % (min,max)
281 return "longueur de liste comprise entre %s et %s" % (self.min,self.max)
283 def info_erreur_liste(self):
284 return "La cardinalité de la liste doit être comprise entre %s et %s" % (self.min,self.max)
287 return self.max == '**' or self.max > 1
289 def get_into(self,liste_courante=None,into_courant=None):
290 if into_courant is None:
292 elif liste_courante is None:
294 elif self.max == '**':
296 elif len(liste_courante) < self.max:
301 def verif_item(self,valeur):
304 def verif(self,valeur):
305 if type(valeur) in (types.ListType,types.TupleType):
306 if self.max != '**' and len(valeur) > self.max:return 0
307 if self.min != '**' and len(valeur) < self.min:return 0
310 if self.max != '**' and 1 > self.max:return 0
311 if self.min != '**' and 1 < self.min:return 0
314 def verif_cata(self):
315 if self.min != '**' and self.max != '**' and self.min > self.max : return 0
318 def valide_liste_partielle(self,liste_courante=None):
320 if liste_courante != None :
321 if len(liste_courante) > self.max :
325 class PairVal(ListVal):
327 Exemple de classe validateur : verification qu'une valeur
329 Pour une liste on verifie que tous les elements sont
336 return "valeur paire"
338 def info_erreur_item(self):
339 return "La valeur saisie doit être paire"
341 def verif_item(self,valeur):
342 if type(valeur) == types.InstanceType:
343 if self.is_eval(valeur):
345 elif self.is_param(valeur):
349 return valeur % 2 == 0
351 def verif(self,valeur):
352 if type(valeur) in (types.ListType,types.TupleType):
354 if val % 2 != 0:return 0
357 if valeur % 2 != 0:return 0
360 class EnumVal(ListVal):
362 Exemple de classe validateur : verification qu'une valeur
363 est prise dans une liste de valeurs.
364 Susceptible de remplacer l attribut "into" dans les catalogues
366 def __init__(self,into=()):
367 if type(into) not in (types.ListType,types.TupleType): into=(into,)
372 return "valeur dans %s" % `self.into`
374 def verif_item(self,valeur):
375 if valeur not in self.into:return 0
381 def get_into(self,liste_courante=None,into_courant=None):
382 if into_courant is None:
383 liste_choix= list(self.into)
386 for e in into_courant:
388 liste_choix.append(e)
391 def info_erreur_item(self):
392 return "La valeur n'est pas dans la liste des choix possibles"
394 class NoRepeat(ListVal):
396 Verification d'absence de doublons dans la liste.
402 return ": pas de présence de doublon dans la liste"
404 def info_erreur_liste(self):
405 return "Les doublons ne sont pas permis"
407 def verif_item(self,valeur):
410 def verif(self,valeur):
411 if type(valeur) in (types.ListType,types.TupleType):
414 if liste.count(val)!=1 : return 0
419 def get_into(self,liste_courante=None,into_courant=None):
421 Methode get_into spécifique pour validateur NoRepeat, on retourne
422 une liste de choix qui ne contient aucune valeur de into_courant
423 déjà contenue dans liste_courante
425 if into_courant is None:
429 for e in into_courant:
430 if e in liste_choix: continue
431 if liste_courante is not None and e in liste_courante: continue
432 liste_choix.append(e)
435 class LongStr(ListVal):
437 Verification de la longueur d une chaine
439 def __init__(self,low,high):
445 return "longueur de la chaine entre %s et %s" %(self.low,self.high)
447 def info_erreur_item(self):
448 return "Longueur de la chaine incorrecte"
450 def verif_item(self,valeur):
453 if valeur[0]=="'" and valeur[-1]=="'" :
456 if len(valeur) < low :return 0
457 if len(valeur) > high:return 0
460 class OrdList(ListVal):
462 Verification qu'une liste est croissante ou decroissante
464 def __init__(self,ord):
469 return "liste %s" % self.ord
471 def info_erreur_liste(self) :
472 return "La liste doit être en ordre "+self.ord
474 def verif(self,valeur):
475 if type(valeur) in (types.ListType,types.TupleType):
476 if self.ord=='croissant':
478 for val in valeur[1:]:
482 elif self.ord=='decroissant':
484 for val in valeur[1:]:
491 def verif_item(self,valeur):
494 def get_into(self,liste_courante=None,into_courant=None):
496 Methode get_into spécifique pour validateur OrdList, on retourne
497 une liste de choix qui ne contient aucune valeur de into_courant
498 dont la valeur est inférieure à la dernière valeur de
499 liste_courante, si elle est différente de None.
501 if into_courant is None:
503 elif not liste_courante :
507 last_val=liste_choix[-1]
508 for e in into_courant:
509 if self.ord=='croissant' and e <= last_val:continue
510 if self.ord=='decroissant' and e >= last_val:continue
511 liste_choix.append(e)
514 CoercableFuncs = { types.IntType: int,
515 types.LongType: long,
516 types.FloatType: float,
517 types.ComplexType: complex,
518 types.UnicodeType: unicode }
520 class TypeVal(ListVal):
522 Cette classe est un validateur qui controle qu'une valeur
523 est bien du type Python attendu.
524 Pour une liste on verifie que tous les elements sont du bon type.
526 def __init__(self, aType):
527 if type(aType) != types.TypeType:
531 self.coerce=CoercableFuncs[ aType ]
533 self.coerce = self.identity
536 return "valeur de %s" % self.aType
538 def identity ( self, value ):
539 if type( value ) == self.aType:
543 def verif_item(self,valeur):
550 class InstanceVal(ListVal):
552 Cette classe est un validateur qui controle qu'une valeur est
553 bien une instance (au sens Python) d'une classe
554 Pour une liste on verifie chaque element de la liste
556 def __init__(self,aClass):
557 if type(aClass) == types.InstanceType:
558 aClass=aClass.__class__
562 return "valeur d'instance de %s" % self.aClass.__name__
564 def verif_item(self,valeur):
565 if not isinstance(valeur,self.aClass): return 0
568 def ImpairVal(valeur):
570 Cette fonction est un validateur. Elle verifie que la valeur passee
571 est bien un nombre impair.
573 if type(valeur) in (types.ListType,types.TupleType):
575 if val % 2 != 1:return 0
578 if valeur % 2 != 1:return 0
581 ImpairVal.info="valeur impaire"
585 Cette classe est un validateur de dictionnaire (mot cle facteur ?). Elle verifie
586 que la somme des cles A et B vaut une valeur donnee
587 en parametre du validateur
589 def __init__(self,somme=10):
594 return "valeur %s pour la somme des cles A et B " % self.somme
596 def verif(self,valeur):
597 if type(valeur) in (types.ListType,types.TupleType):
599 if not val.has_key("A"):return 0
600 if not val.has_key("B"):return 0
601 if val["A"]+val["B"] != self.somme:return 0
604 if not valeur.has_key("A"):return 0
605 if not valeur.has_key("B"):return 0
606 if valeur["A"]+valeur["B"] != self.somme:return 0
609 class FunctionVal(Valid):
611 Cette classe est un validateur qui est initialise avec une fonction
613 def __init__(self,function):
614 self.function=function
617 return self.function.info
619 def verif(self,valeur):
620 return self.function(valeur)
624 Cette classe est un validateur qui controle une liste de validateurs
625 Elle verifie qu'au moins un des validateurs de la liste valide la valeur
627 def __init__(self,validators=()):
628 if type(validators) not in (types.ListType,types.TupleType):
629 validators=(validators,)
631 for validator in validators:
632 if type(validator) == types.FunctionType:
633 self.validators.append(FunctionVal(validator))
635 self.validators.append(validator)
639 return "\n ou ".join([v.info() for v in self.validators])
641 def info_erreur_item(self):
643 for v in self.validators:
644 err=v.info_erreur_item()
645 if err != " " : l.append(err)
646 chaine=" \n ou ".join(l)
649 def info_erreur_liste(self):
651 for v in self.validators:
652 err=v.info_erreur_liste()
653 if err != " " : l.append(err)
654 chaine=" \n ou ".join(l)
659 Si plusieurs validateurs sont reliés par un OU
660 il suffit qu'un seul des validateurs attende une liste
661 pour qu'on considère que leur union attend une liste.
663 for validator in self.validators:
664 v=validator.is_list()
669 def verif(self,valeur):
670 for validator in self.validators:
671 v=validator.verif(valeur)
676 def verif_item(self,valeur):
677 for validator in self.validators:
678 v=validator.verif_item(valeur)
683 def verif_cata(self):
685 for validator in self.validators:
686 v=validator.verif_cata()
687 if not v :infos.append(validator.cata_info)
689 self.cata_info="\n".join(infos)
696 Dans le cas ou plusieurs validateurs sont reliés par un OU
697 il faut que tous les validateurs proposent un choix pour
698 qu'on considère que leur union propose un choix.
699 Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix
700 En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un choix (1,2,3,4,5,6)
702 for validator in self.validators:
703 v=validator.has_into()
708 def get_into(self,liste_courante=None,into_courant=None):
710 Dans le cas ou plusieurs validateurs sont reliés par un OU
711 tous les validateurs doivent proposer un choix pour
712 qu'on considère que leur union propose un choix. Tous les choix
713 proposés par les validateurs sont réunis (opérateur d'union).
714 Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix
715 En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un
719 for validator in self.validators:
720 v_into=validator.get_into(liste_courante,into_courant)
723 validator_into.extend(v_into)
724 return validator_into
726 def valide_liste_partielle(self,liste_courante=None):
728 Méthode de validation de liste partielle pour le validateur Or.
729 Si un des validateurs gérés par le validateur Or considère la
730 liste comme valide, le validateur Or la considère comme valide.
732 for validator in self.validators:
733 v=validator.valide_liste_partielle(liste_courante)
740 Cette classe est un validateur qui controle une liste de validateurs
741 Elle verifie que tous les validateurs de la liste valident la valeur
743 def __init__(self,validators=()):
744 if type(validators) not in (types.ListType,types.TupleType):
745 validators=(validators,)
747 for validator in validators:
748 if type(validator) == types.FunctionType:
749 self.validators.append(FunctionVal(validator))
751 self.validators.append(validator)
755 return "\n et ".join([v.info() for v in self.validators])
757 def info_erreur_item(self):
760 for v in self.validators:
761 if v.info_erreur_item() != " " :
763 chaine=v.info_erreur_item()
766 chaine=chaine+" \n et "+v.info_erreur_item()
769 def info_erreur_liste(self):
771 for v in self.validators:
772 if v.info_erreur_liste() != " " :
774 chaine=v.info_erreur_liste()
777 chaine=chaine+" \n et "+v.info_erreur_liste()
780 def verif(self,valeur):
781 for validator in self.validators:
782 v=validator.verif(valeur)
784 self.local_info=validator.info()
788 def verif_item(self,valeur):
789 for validator in self.validators:
790 v=validator.verif_item(valeur)
792 # L'info n'est probablement pas la meme que pour verif ???
793 self.local_info=validator.info()
797 def verif_cata(self):
799 for validator in self.validators:
800 v=validator.verif_cata()
801 if not v :infos.append(validator.cata_info)
803 self.cata_info="\n".join(infos)
808 def valide_liste_partielle(self,liste_courante=None):
810 Méthode de validation de liste partielle pour le validateur And.
811 Tous les validateurs gérés par le validateur And doivent considérer
812 la liste comme valide, pour que le validateur And la considère
815 for validator in self.validators:
816 v=validator.valide_liste_partielle(liste_courante)
823 Si plusieurs validateurs sont reliés par un ET
824 il faut que tous les validateurs attendent une liste
825 pour qu'on considère que leur intersection attende une liste.
826 Exemple Range(2,5) ET Card(1) n'attend pas une liste
827 Range(2,5) ET Pair attend une liste
829 for validator in self.validators:
830 v=validator.is_list()
837 Dans le cas ou plusieurs validateurs sont reliés par un ET
838 il suffit qu'un seul validateur propose un choix pour
839 qu'on considère que leur intersection propose un choix.
840 Exemple : Enum(1,2,3) ET entier pair, propose un choix
841 En revanche, entier pair ET superieur à 10 ne propose pas de choix
843 for validator in self.validators:
844 v=validator.has_into()
849 def get_into(self,liste_courante=None,into_courant=None):
851 Dans le cas ou plusieurs validateurs sont reliés par un ET
852 il suffit qu'un seul validateur propose un choix pour
853 qu'on considère que leur intersection propose un choix. Tous les
854 choix proposés par les validateurs sont croisés (opérateur
856 Exemple : Enum(1,2,3) ET entier pair, propose un choix (2,)
857 En revanche, Enum(1,2,3) ET Enum(4,5,6) ne propose pas de choix.
859 for validator in self.validators:
860 into_courant=validator.get_into(liste_courante,into_courant)
861 if into_courant in ([],None):break
864 def do_liste(validators):
866 Convertit une arborescence de validateurs en OrVal ou AndVal
867 validators est une liste de validateurs ou de listes ou de tuples
870 for validator in validators:
871 if type(validator) == types.FunctionType:
872 valids.append(FunctionVal(validator))
873 elif type(validator) == types.TupleType:
874 valids.append(OrVal(do_liste(validator)))
875 elif type(validator) == types.ListType:
876 valids.append(AndVal(do_liste(validator)))
878 valids.append(validator)
881 def validatorFactory(validator):
882 if type(validator) == types.FunctionType:
883 return FunctionVal(validator)
884 elif type(validator) == types.TupleType:
885 return OrVal(do_liste(validator))
886 elif type(validator) == types.ListType:
887 return AndVal(do_liste(validator))