1 #@ MODIF N_VALIDATOR Noyau DATE 20/09/2004 AUTEUR DURAND C.DURAND
2 # -*- coding: iso-8859-1 -*-
3 # CONFIGURATION MANAGEMENT OF EDF VERSION
4 # ======================================================================
5 # COPYRIGHT (C) 1991 - 2003 EDF R&D WWW.CODE-ASTER.ORG
6 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
7 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
8 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR
9 # (AT YOUR OPTION) ANY LATER VERSION.
11 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT
12 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
13 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU
14 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.
16 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE
17 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,
18 # 1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.
19 # ======================================================================
22 Ce module contient toutes les classes necessaires pour
23 implanter le concept de validateur dans Accas
25 import types,exceptions
27 class ValError ( exceptions.Exception ):
32 Cette classe est la classe mere des validateurs Accas
33 Elle doit etre derivee
34 Elle presente la signature des methodes indispensables pour son bon
35 fonctionnement et dans certains cas leur comportement par défaut.
37 @ivar cata_info: raison de la validite ou de l'invalidite du validateur meme
38 @type cata_info: C{string}
40 def __init__(self,*tup,**args):
42 Cette methode sert a initialiser les attributs du validateur
45 raise "Must be implemented"
49 Cette methode retourne une chaine de caractères informative sur
50 la validation demandée par le validateur. Elle est utilisée
51 pour produire le compte-rendu de validité du mot clé associé.
53 return "valeur valide"
57 Cette methode retourne une chaine de caractère qui permet
58 de construire un message d'aide en ligne.
59 En général, le message retourné est le meme que celui retourné par la
64 def info_erreur_item(self):
66 Cette méthode permet d'avoir un message d'erreur pour un item
67 dans une liste dans le cas ou le validateur fait des vérifications
68 sur les items d'une liste. Si le validateur fait seulement des
69 vérifications sur la liste elle meme et non sur ses items, la méthode
70 doit retourner une chaine vide.
74 def info_erreur_liste(self):
76 Cette méthode a un comportement complémentaire de celui de
77 info_erreur_item. Elle retourne un message d'erreur lié uniquement
78 aux vérifications sur la liste elle meme et pas sur ses items.
79 Dans le cas où le validateur ne fait pas de vérification sur des
80 listes, elle retourne une chaine vide
84 def verif(self,valeur):
86 Cette methode sert a verifier si la valeur passee en argument est consideree
87 comme valide ou non par le validateur. Dans le premier cas le validateur retourne 1
88 (valide) sinon 0 (invalide).
90 @type valeur: tout type python
91 @param valeur: valeur du mot cle a valider
93 @return: indicateur de validite 1 (valide) ou 0 (invalide)
95 raise "Must be implemented"
97 def verif_item(self,valeur):
99 La methode verif du validateur effectue une validation complete de
100 la valeur. valeur peut etre un scalaire ou une liste. Le validateur
101 doit traiter les 2 aspects s'il accepte des listes (dans ce cas la
102 methode is_list doit retourner 1).
103 La methode valid_item sert pour effectuer des validations partielles
104 de liste. Elle doit uniquement verifier la validite d'un item de
105 liste mais pas les caracteristiques de la liste.
109 def valide_liste_partielle(self,liste_courante):
111 Cette methode retourne un entier qui indique si liste_courante est partiellement valide (valeur 1)
112 ou invalide (valeur 0). La validation partielle concerne les listes en cours de construction : on
113 veut savoir si la liste en construction peut etre complétée ou si elle peut déjà etre considérée
115 En général un validateur effectue la meme validation pour les listes partielles et les
118 return self.verif(liste_courante)
120 def verif_cata(self):
122 Cette methode sert a realiser des verifications du validateur lui meme.
123 Elle est facultative et retourne 1 (valide) par defaut.
124 Elle retourne 0 si le validateur est lui meme invalide si par exemple ses
125 parametres de definition ne sont pas corrects.
126 La raison de l'invalidite est stockee dans l'attribut cata_info.
129 @return: indicateur de validite 1 (valide) ou 0 (invalide)
135 Cette méthode retourne un entier qui indique si le validateur
136 permet les listes (valeur 1) ou ne les permet pas (valeur 0).
137 Par défaut, un validateur n'autorise que des scalaires.
143 Cette méthode retourne un entier qui indique si le validateur
144 propose une liste de choix (valeur 1) ou n'en propose pas.
145 Par défaut, un validateur n'en propose pas.
149 def get_into(self,liste_courante=None,into_courant=None):
151 Cette méthode retourne la liste de choix proposée par le validateur.
152 Si le validateur ne propose pas de liste de choix, la méthode
154 L'argument d'entrée liste_courante, s'il est différent de None, donne
155 la liste des choix déjà effectués par l'utilisateur. Dans ce cas, la
156 méthode get_into doit calculer la liste des choix en en tenant
157 compte. Par exemple, si le validateur n'autorise pas les répétitions,
158 la liste des choix retournée ne doit pas contenir les choix déjà
159 contenus dans liste_courante.
160 L'argument d'entrée into_courant, s'il est différent de None, donne
161 la liste des choix proposés par d'autres validateurs. Dans ce cas,
162 la méthode get_into doit calculer la liste des choix à retourner
163 en se limitant à cette liste initiale. Par exemple, si into_courant
164 vaut (1,2,3) et que le validateur propose la liste de choix (3,4,5),
165 la méthode ne doit retourner que (3,).
167 La méthode get_into peut retourner une liste vide [], ce qui veut
168 dire qu'il n'y a pas (ou plus) de choix possible. Cette situation
169 peut etre normale : l''utilisateur a utilisé tous les choix, ou
170 résulter d'une incohérence des validateurs :
171 choix parmi (1,2,3) ET choix parmi (4,5,6). Il est impossible de
172 faire la différence entre ces deux situations.
176 def is_param(self,valeur):
178 Cette méthode indique si valeur est un objet de type PARAMETRE
179 dont on cherchera à evaluer la valeur (valeur.valeur)
181 return type(valeur) == types.InstanceType and valeur.__class__.__name__ in ('PARAMETRE',)
183 def is_unknown(self,valeur):
185 Cette méthode indique si valeur est un objet de type inconnu
186 c'est à dire pas de type PARAMETRE
188 return type(valeur) == types.InstanceType and valeur.__class__.__name__ not in (
189 'entier','reel','chaine', 'complexe','liste','PARAMETRE_EVAL','PARAMETRE')
191 class ListVal(Valid):
193 Cette classe sert de classe mère pour tous les validateurs qui acceptent
199 def get_into(self,liste_courante=None,into_courant=None):
201 Cette méthode get_into effectue un traitement général qui consiste
202 a filtrer la liste de choix into_courant, si elle existe, en ne
203 conservant que les valeurs valides (appel de la méthode valid).
205 if into_courant is None:
209 for e in into_courant:
211 liste_choix.append(e)
214 def verif(self,valeur):
216 Méthode verif pour les validateurs de listes. Cette méthode
217 fait appel à la méthode verif_item sur chaque élément de la
218 liste. Si valeur est un paramètre, on utilise sa valeur effective
221 if self.is_param(valeur):
223 if type(valeur) in (types.ListType,types.TupleType):
225 if not self.verif_item(val):
229 return self.verif_item(valeur)
231 class RangeVal(ListVal):
233 Exemple de classe validateur : verification qu'une valeur
234 est dans un intervalle.
235 Pour une liste on verifie que tous les elements sont
237 Susceptible de remplacer les attributs "vale_min" "vale_max"
240 def __init__(self,low,high):
243 self.cata_info="%s doit etre inferieur a %s" %(low,high)
246 return "valeur dans l'intervalle %s , %s" %(self.low,self.high)
248 def verif_item(self,valeur):
249 return valeur > self.low and valeur < self.high
251 def info_erreur_item(self) :
252 return "La valeur doit etre comprise entre %s et %s" % (self.low,
255 def verif_cata(self):
256 if self.low > self.high : return 0
259 class CardVal(Valid):
261 Exemple de classe validateur : verification qu'une liste est
262 d'une longueur superieur a un minimum (min) et inferieure
264 Susceptible de remplacer les attributs "min" "max" dans les
267 def __init__(self,min='**',max='**'):
270 self.cata_info="%s doit etre inferieur a %s" % (min,max)
273 return "longueur de liste comprise entre %s et %s" % (self.min,self.max)
275 def info_erreur_liste(self):
276 return "Le cardinal de la liste doit etre compris entre %s et %s" % (self.min,self.max)
279 return self.max == '**' or self.max > 1
281 def get_into(self,liste_courante=None,into_courant=None):
282 if into_courant is None:
284 elif liste_courante is None:
286 elif self.max == '**':
288 elif len(liste_courante) < self.max:
293 def verif_item(self,valeur):
296 def verif(self,valeur):
297 if type(valeur) in (types.ListType,types.TupleType):
298 if self.max != '**' and len(valeur) > self.max:return 0
299 if self.min != '**' and len(valeur) < self.min:return 0
302 if self.max != '**' and 1 > self.max:return 0
303 if self.min != '**' and 1 < self.min:return 0
306 def verif_cata(self):
307 if self.min != '**' and self.max != '**' and self.min > self.max : return 0
310 def valide_liste_partielle(self,liste_courante=None):
312 if liste_courante != None :
313 if len(liste_courante) > self.max :
317 class PairVal(ListVal):
319 Exemple de classe validateur : verification qu'une valeur
321 Pour une liste on verifie que tous les elements sont
328 return "valeur paire"
330 def info_erreur_item(self):
331 return "La valeur saisie doit etre paire"
333 def verif_item(self,valeur):
334 if type(valeur) == types.InstanceType:
335 if self.is_param(valeur):
339 return valeur % 2 == 0
341 def verif(self,valeur):
342 if type(valeur) in (types.ListType,types.TupleType):
344 if val % 2 != 0:return 0
347 if valeur % 2 != 0:return 0
350 class EnumVal(ListVal):
352 Exemple de classe validateur : verification qu'une valeur
353 est prise dans une liste de valeurs.
354 Susceptible de remplacer l attribut "into" dans les catalogues
356 def __init__(self,into=()):
357 if type(into) not in (types.ListType,types.TupleType): into=(into,)
362 return "valeur dans %s" % `self.into`
364 def verif_item(self,valeur):
365 if valeur not in self.into:return 0
371 def get_into(self,liste_courante=None,into_courant=None):
372 if into_courant is None:
373 liste_choix= list(self.into)
376 for e in into_courant:
378 liste_choix.append(e)
381 def info_erreur_item(self):
382 return "La valeur n'est pas dans la liste des choix possibles"
384 class NoRepeat(ListVal):
386 Verification d'absence de doublons dans la liste.
392 return ": pas de présence de doublon dans la liste"
394 def info_erreur_liste(self):
395 return "Les doublons ne sont pas permis"
397 def verif_item(self,valeur):
400 def verif(self,valeur):
401 if type(valeur) in (types.ListType,types.TupleType):
404 if liste.count(val)!=1 : return 0
409 def get_into(self,liste_courante=None,into_courant=None):
411 Methode get_into spécifique pour validateur NoRepeat, on retourne
412 une liste de choix qui ne contient aucune valeur de into_courant
413 déjà contenue dans liste_courante
415 if into_courant is None:
419 for e in into_courant:
420 if e in liste_choix: continue
421 if liste_courante is not None and e in liste_courante: continue
422 liste_choix.append(e)
425 class LongStr(ListVal):
427 Verification de la longueur d une chaine
429 def __init__(self,low,high):
435 return "longueur de la chaine entre %s et %s" %(self.low,self.high)
437 def info_erreur_item(self):
438 return "Longueur de la chaine incorrecte"
440 def verif_item(self,valeur):
443 if valeur[0]=="'" and valeur[-1]=="'" :
446 if len(valeur) < low :return 0
447 if len(valeur) > high:return 0
450 class OrdList(ListVal):
452 Verification qu'une liste est croissante ou decroissante
454 def __init__(self,ord):
459 return "liste %s" % self.ord
461 def info_erreur_liste(self) :
462 return "La liste doit etre en ordre "+self.ord
464 def verif(self,valeur):
465 if type(valeur) in (types.ListType,types.TupleType):
466 if self.ord=='croissant':
468 for val in valeur[1:]:
472 elif self.ord=='decroissant':
474 for val in valeur[1:]:
481 def verif_item(self,valeur):
484 def get_into(self,liste_courante=None,into_courant=None):
486 Methode get_into spécifique pour validateur OrdList, on retourne
487 une liste de choix qui ne contient aucune valeur de into_courant
488 dont la valeur est inférieure à la dernière valeur de
489 liste_courante, si elle est différente de None.
491 if into_courant is None:
493 elif not liste_courante :
497 last_val=liste_choix[-1]
498 for e in into_courant:
499 if self.ord=='croissant' and e <= last_val:continue
500 if self.ord=='decroissant' and e >= last_val:continue
501 liste_choix.append(e)
504 CoercableFuncs = { types.IntType: int,
505 types.LongType: long,
506 types.FloatType: float,
507 types.ComplexType: complex,
508 types.UnicodeType: unicode }
510 class TypeVal(ListVal):
512 Cette classe est un validateur qui controle qu'une valeur
513 est bien du type Python attendu.
514 Pour une liste on verifie que tous les elements sont du bon type.
516 def __init__(self, aType):
517 if type(aType) != types.TypeType:
521 self.coerce=CoercableFuncs[ aType ]
523 self.coerce = self.identity
526 return "valeur de %s" % self.aType
528 def identity ( self, value ):
529 if type( value ) == self.aType:
533 def verif_item(self,valeur):
540 class InstanceVal(ListVal):
542 Cette classe est un validateur qui controle qu'une valeur est
543 bien une instance (au sens Python) d'une classe
544 Pour une liste on verifie chaque element de la liste
546 def __init__(self,aClass):
547 if type(aClass) == types.InstanceType:
548 aClass=aClass.__class__
552 return "valeur d'instance de %s" % self.aClass.__name__
554 def verif_item(self,valeur):
555 if not isinstance(valeur,self.aClass): return 0
558 def ImpairVal(valeur):
560 Cette fonction est un validateur. Elle verifie que la valeur passee
561 est bien un nombre impair.
563 if type(valeur) in (types.ListType,types.TupleType):
565 if val % 2 != 1:return 0
568 if valeur % 2 != 1:return 0
571 ImpairVal.info="valeur impaire"
575 Cette classe est un validateur de dictionnaire (mot cle facteur ?). Elle verifie
576 que la somme des cles A et B vaut une valeur donnee
577 en parametre du validateur
579 def __init__(self,somme=10):
584 return "valeur %s pour la somme des cles A et B " % self.somme
586 def verif(self,valeur):
587 if type(valeur) in (types.ListType,types.TupleType):
589 if not val.has_key("A"):return 0
590 if not val.has_key("B"):return 0
591 if val["A"]+val["B"] != self.somme:return 0
594 if not valeur.has_key("A"):return 0
595 if not valeur.has_key("B"):return 0
596 if valeur["A"]+valeur["B"] != self.somme:return 0
599 class FunctionVal(Valid):
601 Cette classe est un validateur qui est initialise avec une fonction
603 def __init__(self,function):
604 self.function=function
607 return self.function.info
609 def verif(self,valeur):
610 return self.function(valeur)
614 Cette classe est un validateur qui controle une liste de validateurs
615 Elle verifie qu'au moins un des validateurs de la liste valide la valeur
617 def __init__(self,validators=()):
618 if type(validators) not in (types.ListType,types.TupleType):
619 validators=(validators,)
621 for validator in validators:
622 if type(validator) == types.FunctionType:
623 self.validators.append(FunctionVal(validator))
625 self.validators.append(validator)
629 return "\n ou ".join([v.info() for v in self.validators])
631 def info_erreur_item(self):
633 for v in self.validators:
634 err=v.info_erreur_item()
635 if err != " " : l.append(err)
636 chaine=" \n ou ".join(l)
639 def info_erreur_liste(self):
641 for v in self.validators:
642 err=v.info_erreur_liste()
643 if err != " " : l.append(err)
644 chaine=" \n ou ".join(l)
649 Si plusieurs validateurs sont reliés par un OU
650 il suffit qu'un seul des validateurs attende une liste
651 pour qu'on considère que leur union attend une liste.
653 for validator in self.validators:
654 v=validator.is_list()
659 def verif(self,valeur):
660 for validator in self.validators:
661 v=validator.verif(valeur)
666 def verif_item(self,valeur):
667 for validator in self.validators:
668 v=validator.verif_item(valeur)
673 def verif_cata(self):
675 for validator in self.validators:
676 v=validator.verif_cata()
677 if not v :infos.append(validator.cata_info)
679 self.cata_info="\n".join(infos)
686 Dans le cas ou plusieurs validateurs sont reliés par un OU
687 il faut que tous les validateurs proposent un choix pour
688 qu'on considère que leur union propose un choix.
689 Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix
690 En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un choix (1,2,3,4,5,6)
692 for validator in self.validators:
693 v=validator.has_into()
698 def get_into(self,liste_courante=None,into_courant=None):
700 Dans le cas ou plusieurs validateurs sont reliés par un OU
701 tous les validateurs doivent proposer un choix pour
702 qu'on considère que leur union propose un choix. Tous les choix
703 proposés par les validateurs sont réunis (opérateur d'union).
704 Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix
705 En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un
709 for validator in self.validators:
710 v_into=validator.get_into(liste_courante,into_courant)
713 validator_into.extend(v_into)
714 return validator_into
716 def valide_liste_partielle(self,liste_courante=None):
718 Méthode de validation de liste partielle pour le validateur Or.
719 Si un des validateurs gérés par le validateur Or considère la
720 liste comme valide, le validateur Or la considère comme valide.
722 for validator in self.validators:
723 v=validator.valide_liste_partielle(liste_courante)
730 Cette classe est un validateur qui controle une liste de validateurs
731 Elle verifie que tous les validateurs de la liste valident la valeur
733 def __init__(self,validators=()):
734 if type(validators) not in (types.ListType,types.TupleType):
735 validators=(validators,)
737 for validator in validators:
738 if type(validator) == types.FunctionType:
739 self.validators.append(FunctionVal(validator))
741 self.validators.append(validator)
745 return "\n et ".join([v.info() for v in self.validators])
747 def info_erreur_item(self):
750 for v in self.validators:
751 if v.info_erreur_item() != " " :
753 chaine=v.info_erreur_item()
756 chaine=chaine+" \n et "+v.info_erreur_item()
759 def info_erreur_liste(self):
761 for v in self.validators:
762 if v.info_erreur_liste() != " " :
764 chaine=v.info_erreur_liste()
767 chaine=chaine+" \n et "+v.info_erreur_liste()
770 def verif(self,valeur):
771 for validator in self.validators:
772 v=validator.verif(valeur)
774 self.local_info=validator.info()
778 def verif_item(self,valeur):
779 for validator in self.validators:
780 v=validator.verif_item(valeur)
782 # L'info n'est probablement pas la meme que pour verif ???
783 self.local_info=validator.info()
787 def verif_cata(self):
789 for validator in self.validators:
790 v=validator.verif_cata()
791 if not v :infos.append(validator.cata_info)
793 self.cata_info="\n".join(infos)
798 def valide_liste_partielle(self,liste_courante=None):
800 Méthode de validation de liste partielle pour le validateur And.
801 Tous les validateurs gérés par le validateur And doivent considérer
802 la liste comme valide, pour que le validateur And la considère
805 for validator in self.validators:
806 v=validator.valide_liste_partielle(liste_courante)
813 Si plusieurs validateurs sont reliés par un ET
814 il faut que tous les validateurs attendent une liste
815 pour qu'on considère que leur intersection attende une liste.
816 Exemple Range(2,5) ET Card(1) n'attend pas une liste
817 Range(2,5) ET Pair attend une liste
819 for validator in self.validators:
820 v=validator.is_list()
827 Dans le cas ou plusieurs validateurs sont reliés par un ET
828 il suffit qu'un seul validateur propose un choix pour
829 qu'on considère que leur intersection propose un choix.
830 Exemple : Enum(1,2,3) ET entier pair, propose un choix
831 En revanche, entier pair ET superieur à 10 ne propose pas de choix
833 for validator in self.validators:
834 v=validator.has_into()
839 def get_into(self,liste_courante=None,into_courant=None):
841 Dans le cas ou plusieurs validateurs sont reliés par un ET
842 il suffit qu'un seul validateur propose un choix pour
843 qu'on considère que leur intersection propose un choix. Tous les
844 choix proposés par les validateurs sont croisés (opérateur
846 Exemple : Enum(1,2,3) ET entier pair, propose un choix (2,)
847 En revanche, Enum(1,2,3) ET Enum(4,5,6) ne propose pas de choix.
849 for validator in self.validators:
850 into_courant=validator.get_into(liste_courante,into_courant)
851 if into_courant in ([],None):break
854 def do_liste(validators):
856 Convertit une arborescence de validateurs en OrVal ou AndVal
857 validators est une liste de validateurs ou de listes ou de tuples
860 for validator in validators:
861 if type(validator) == types.FunctionType:
862 valids.append(FunctionVal(validator))
863 elif type(validator) == types.TupleType:
864 valids.append(OrVal(do_liste(validator)))
865 elif type(validator) == types.ListType:
866 valids.append(AndVal(do_liste(validator)))
868 valids.append(validator)
871 def validatorFactory(validator):
872 if type(validator) == types.FunctionType:
873 return FunctionVal(validator)
874 elif type(validator) == types.TupleType:
875 return OrVal(do_liste(validator))
876 elif type(validator) == types.ListType:
877 return AndVal(do_liste(validator))