1 # -*- coding: utf-8 -*-
2 #@ MODIF N_VALIDATOR Noyau DATE 04/02/2004 AUTEUR CAMBIER S.CAMBIER
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 # ======================================================================
21 Ce module contient toutes les classes necessaires pour
22 implanter le concept de validateur dans Accas
24 import types,exceptions
26 class ValError ( exceptions.Exception ):
31 Cette classe est la classe mere des validateurs Accas
32 Elle doit etre derivee
33 Elle presente la signature des methodes indispensables pour son bon
34 fonctionnement et dans certains cas leur comportement par défaut.
36 @ivar cata_info: raison de la validite ou de l'invalidite du validateur meme
37 @type cata_info: C{string}
39 def __init__(self,*tup,**args):
41 Cette methode sert a initialiser les attributs du validateur
44 raise "Must be implemented"
48 Cette methode retourne une chaine de caractères informative sur
49 la validation demandée par le validateur. Elle est utilisée
50 pour produire le compte-rendu de validité du mot clé associé.
52 return "valeur valide"
56 Cette methode retourne une chaine de caractère qui permet
57 de construire un message d'aide en ligne.
58 En général, le message retourné est le meme que celui retourné par la
63 def info_erreur_item(self):
65 Cette méthode permet d'avoir un message d'erreur pour un item
66 dans une liste dans le cas ou le validateur fait des vérifications
67 sur les items d'une liste. Si le validateur fait seulement des
68 vérifications sur la liste elle meme et non sur ses items, la méthode
69 doit retourner une chaine vide.
73 def info_erreur_liste(self):
75 Cette méthode a un comportement complémentaire de celui de
76 info_erreur_item. Elle retourne un message d'erreur lié uniquement
77 aux vérifications sur la liste elle meme et pas sur ses items.
78 Dans le cas où le validateur ne fait pas de vérification sur des
79 listes, elle retourne une chaine vide
83 def verif(self,valeur):
85 Cette methode sert a verifier si la valeur passee en argument est consideree
86 comme valide ou non par le validateur. Dans le premier cas le validateur retourne 1
87 (valide) sinon 0 (invalide).
89 @type valeur: tout type python
90 @param valeur: valeur du mot cle a valider
92 @return: indicateur de validite 1 (valide) ou 0 (invalide)
94 raise "Must be implemented"
96 def verif_item(self,valeur):
98 La methode verif du validateur effectue une validation complete de
99 la valeur. valeur peut etre un scalaire ou une liste. Le validateur
100 doit traiter les 2 aspects s'il accepte des listes (dans ce cas la
101 methode is_list doit retourner 1).
102 La methode valid_item sert pour effectuer des validations partielles
103 de liste. Elle doit uniquement verifier la validite d'un item de
104 liste mais pas les caracteristiques de la liste.
108 def valide_liste_partielle(self,liste_courante):
110 Cette methode retourne un entier qui indique si liste_courante est partiellement valide (valeur 1)
111 ou invalide (valeur 0). La validation partielle concerne les listes en cours de construction : on
112 veut savoir si la liste en construction peut etre complétée ou si elle peut déjà etre considérée
114 En général un validateur effectue la meme validation pour les listes partielles et les
117 return self.verif(liste_courante)
119 def verif_cata(self):
121 Cette methode sert a realiser des verifications du validateur lui meme.
122 Elle est facultative et retourne 1 (valide) par defaut.
123 Elle retourne 0 si le validateur est lui meme invalide si par exemple ses
124 parametres de definition ne sont pas corrects.
125 La raison de l'invalidite est stockee dans l'attribut cata_info.
128 @return: indicateur de validite 1 (valide) ou 0 (invalide)
134 Cette méthode retourne un entier qui indique si le validateur
135 permet les listes (valeur 1) ou ne les permet pas (valeur 0).
136 Par défaut, un validateur n'autorise que des scalaires.
142 Cette méthode retourne un entier qui indique si le validateur
143 propose une liste de choix (valeur 1) ou n'en propose pas.
144 Par défaut, un validateur n'en propose pas.
148 def get_into(self,liste_courante=None,into_courant=None):
150 Cette méthode retourne la liste de choix proposée par le validateur.
151 Si le validateur ne propose pas de liste de choix, la méthode
153 L'argument d'entrée liste_courante, s'il est différent de None, donne
154 la liste des choix déjà effectués par l'utilisateur. Dans ce cas, la
155 méthode get_into doit calculer la liste des choix en en tenant
156 compte. Par exemple, si le validateur n'autorise pas les répétitions,
157 la liste des choix retournée ne doit pas contenir les choix déjà
158 contenus dans liste_courante.
159 L'argument d'entrée into_courant, s'il est différent de None, donne
160 la liste des choix proposés par d'autres validateurs. Dans ce cas,
161 la méthode get_into doit calculer la liste des choix à retourner
162 en se limitant à cette liste initiale. Par exemple, si into_courant
163 vaut (1,2,3) et que le validateur propose la liste de choix (3,4,5),
164 la méthode ne doit retourner que (3,).
166 La méthode get_into peut retourner une liste vide [], ce qui veut
167 dire qu'il n'y a pas (ou plus) de choix possible. Cette situation
168 peut etre normale : l''utilisateur a utilisé tous les choix, ou
169 résulter d'une incohérence des validateurs :
170 choix parmi (1,2,3) ET choix parmi (4,5,6). Il est impossible de
171 faire la différence entre ces deux situations.
175 def is_eval(self,valeur):
177 Cette méthode indique si valeur est un objet de type EVAL ou autre
178 que l'on ne cherchera pas à evaluer et qui doit etre considere
179 comme toujours valide. Si c'est un objet de ce type elle retourne
180 la valeur 1 sinon la valeur 0
182 return type(valeur) == types.InstanceType and valeur.__class__.__name__ in ('EVAL',
183 'entier','reel','chaine', 'complexe','liste','PARAMETRE_EVAL')
185 def is_param(self,valeur):
187 Cette méthode indique si valeur est un objet de type PARAMETRE
188 dont on cherchera à evaluer la valeur (valeur.valeur)
190 return type(valeur) == types.InstanceType and valeur.__class__.__name__ in ('PARAMETRE',)
192 def is_unknown(self,valeur):
194 Cette méthode indique si valeur est un objet de type inconnu
195 c'est à dire ni de type EVAL ni de type PARAMETRE
197 return type(valeur) == types.InstanceType and valeur.__class__.__name__ not in ('EVAL',
198 'entier','reel','chaine', 'complexe','liste','PARAMETRE_EVAL','PARAMETRE')
200 class ListVal(Valid):
202 Cette classe sert de classe mère pour tous les validateurs qui acceptent
208 def get_into(self,liste_courante=None,into_courant=None):
210 Cette méthode get_into effectue un traitement général qui consiste
211 a filtrer la liste de choix into_courant, si elle existe, en ne
212 conservant que les valeurs valides (appel de la méthode valid).
214 if into_courant is None:
218 for e in into_courant:
220 liste_choix.append(e)
223 def verif(self,valeur):
225 Méthode verif pour les validateurs de listes. Cette méthode
226 fait appel à la méthode verif_item sur chaque élément de la
227 liste. Si valeur est un paramètre, on utilise sa valeur effective
230 if self.is_param(valeur):
232 if type(valeur) in (types.ListType,types.TupleType):
234 if not self.verif_item(val):
238 return self.verif_item(valeur)
240 class RangeVal(ListVal):
242 Exemple de classe validateur : verification qu'une valeur
243 est dans un intervalle.
244 Pour une liste on verifie que tous les elements sont
246 Susceptible de remplacer les attributs "vale_min" "vale_max"
249 def __init__(self,low,high):
252 self.cata_info="%s doit etre inferieur a %s" %(low,high)
255 return "valeur dans l'intervalle %s , %s" %(self.low,self.high)
257 def verif_item(self,valeur):
258 return valeur > self.low and valeur < self.high
260 def info_erreur_item(self) :
261 return "La valeur doit etre comprise entre %s et %s" % (self.low,
264 def verif_cata(self):
265 if self.low > self.high : return 0
268 class CardVal(Valid):
270 Exemple de classe validateur : verification qu'une liste est
271 d'une longueur superieur a un minimum (min) et inferieure
273 Susceptible de remplacer les attributs "min" "max" dans les
276 def __init__(self,min='**',max='**'):
279 self.cata_info="%s doit etre inferieur a %s" % (min,max)
282 return "longueur de liste comprise entre %s et %s" % (self.min,self.max)
284 def info_erreur_liste(self):
285 return "Le cardinal de la liste doit etre compris entre %s et %s" % (self.min,self.max)
288 return self.max == '**' or self.max > 1
290 def get_into(self,liste_courante=None,into_courant=None):
291 if into_courant is None:
293 elif liste_courante is None:
295 elif self.max == '**':
297 elif len(liste_courante) < self.max:
302 def verif_item(self,valeur):
305 def verif(self,valeur):
306 if type(valeur) in (types.ListType,types.TupleType):
307 if self.max != '**' and len(valeur) > self.max:return 0
308 if self.min != '**' and len(valeur) < self.min:return 0
311 if self.max != '**' and 1 > self.max:return 0
312 if self.min != '**' and 1 < self.min:return 0
315 def verif_cata(self):
316 if self.min != '**' and self.max != '**' and self.min > self.max : return 0
319 def valide_liste_partielle(self,liste_courante=None):
321 if liste_courante != None :
322 if len(liste_courante) > self.max :
326 class PairVal(ListVal):
328 Exemple de classe validateur : verification qu'une valeur
330 Pour une liste on verifie que tous les elements sont
337 return "valeur paire"
339 def info_erreur_item(self):
340 return "La valeur saisie doit etre paire"
342 def verif_item(self,valeur):
343 if type(valeur) == types.InstanceType:
344 if self.is_eval(valeur):
346 elif self.is_param(valeur):
350 return valeur % 2 == 0
352 def verif(self,valeur):
353 if type(valeur) in (types.ListType,types.TupleType):
355 if val % 2 != 0:return 0
358 if valeur % 2 != 0:return 0
361 class EnumVal(ListVal):
363 Exemple de classe validateur : verification qu'une valeur
364 est prise dans une liste de valeurs.
365 Susceptible de remplacer l attribut "into" dans les catalogues
367 def __init__(self,into=()):
368 if type(into) not in (types.ListType,types.TupleType): into=(into,)
373 return "valeur dans %s" % `self.into`
375 def verif_item(self,valeur):
376 if valeur not in self.into:return 0
382 def get_into(self,liste_courante=None,into_courant=None):
383 if into_courant is None:
384 liste_choix= list(self.into)
387 for e in into_courant:
389 liste_choix.append(e)
392 def info_erreur_item(self):
393 return "La valeur n'est pas dans la liste des choix possibles"
395 class NoRepeat(ListVal):
397 Verification d'absence de doublons dans la liste.
403 return ": pas de présence de doublon dans la liste"
405 def info_erreur_liste(self):
406 return "Les doublons ne sont pas permis"
408 def verif_item(self,valeur):
411 def verif(self,valeur):
412 if type(valeur) in (types.ListType,types.TupleType):
415 if liste.count(val)!=1 : return 0
420 def get_into(self,liste_courante=None,into_courant=None):
422 Methode get_into spécifique pour validateur NoRepeat, on retourne
423 une liste de choix qui ne contient aucune valeur de into_courant
424 déjà contenue dans liste_courante
426 if into_courant is None:
430 for e in into_courant:
431 if e in liste_choix: continue
432 if liste_courante is not None and e in liste_courante: continue
433 liste_choix.append(e)
436 class LongStr(ListVal):
438 Verification de la longueur d une chaine
440 def __init__(self,low,high):
446 return "longueur de la chaine entre %s et %s" %(self.low,self.high)
448 def info_erreur_item(self):
449 return "Longueur de la chaine incorrecte"
451 def verif_item(self,valeur):
454 if valeur[0]=="'" and valeur[-1]=="'" :
457 if len(valeur) < low :return 0
458 if len(valeur) > high:return 0
461 class OrdList(ListVal):
463 Verification qu'une liste est croissante ou decroissante
465 def __init__(self,ord):
470 return "liste %s" % self.ord
472 def info_erreur_liste(self) :
473 return "La liste doit etre en ordre "+self.ord
475 def verif(self,valeur):
476 if type(valeur) in (types.ListType,types.TupleType):
477 if self.ord=='croissant':
479 for val in valeur[1:]:
483 elif self.ord=='decroissant':
485 for val in valeur[1:]:
492 def verif_item(self,valeur):
495 def get_into(self,liste_courante=None,into_courant=None):
497 Methode get_into spécifique pour validateur OrdList, on retourne
498 une liste de choix qui ne contient aucune valeur de into_courant
499 dont la valeur est inférieure à la dernière valeur de
500 liste_courante, si elle est différente de None.
502 if into_courant is None:
504 elif not liste_courante :
508 last_val=liste_choix[-1]
509 for e in into_courant:
510 if self.ord=='croissant' and e <= last_val:continue
511 if self.ord=='decroissant' and e >= last_val:continue
512 liste_choix.append(e)
515 CoercableFuncs = { types.IntType: int,
516 types.LongType: long,
517 types.FloatType: float,
518 types.ComplexType: complex,
519 types.UnicodeType: unicode }
521 class TypeVal(ListVal):
523 Cette classe est un validateur qui controle qu'une valeur
524 est bien du type Python attendu.
525 Pour une liste on verifie que tous les elements sont du bon type.
527 def __init__(self, aType):
528 if type(aType) != types.TypeType:
532 self.coerce=CoercableFuncs[ aType ]
534 self.coerce = self.identity
537 return "valeur de %s" % self.aType
539 def identity ( self, value ):
540 if type( value ) == self.aType:
544 def verif_item(self,valeur):
551 class InstanceVal(ListVal):
553 Cette classe est un validateur qui controle qu'une valeur est
554 bien une instance (au sens Python) d'une classe
555 Pour une liste on verifie chaque element de la liste
557 def __init__(self,aClass):
558 if type(aClass) == types.InstanceType:
559 aClass=aClass.__class__
563 return "valeur d'instance de %s" % self.aClass.__name__
565 def verif_item(self,valeur):
566 if not isinstance(valeur,self.aClass): return 0
569 def ImpairVal(valeur):
571 Cette fonction est un validateur. Elle verifie que la valeur passee
572 est bien un nombre impair.
574 if type(valeur) in (types.ListType,types.TupleType):
576 if val % 2 != 1:return 0
579 if valeur % 2 != 1:return 0
582 ImpairVal.info="valeur impaire"
586 Cette classe est un validateur de dictionnaire (mot cle facteur ?). Elle verifie
587 que la somme des cles A et B vaut une valeur donnee
588 en parametre du validateur
590 def __init__(self,somme=10):
595 return "valeur %s pour la somme des cles A et B " % self.somme
597 def verif(self,valeur):
598 if type(valeur) in (types.ListType,types.TupleType):
600 if not val.has_key("A"):return 0
601 if not val.has_key("B"):return 0
602 if val["A"]+val["B"] != self.somme:return 0
605 if not valeur.has_key("A"):return 0
606 if not valeur.has_key("B"):return 0
607 if valeur["A"]+valeur["B"] != self.somme:return 0
610 class FunctionVal(Valid):
612 Cette classe est un validateur qui est initialise avec une fonction
614 def __init__(self,function):
615 self.function=function
618 return self.function.info
620 def verif(self,valeur):
621 return self.function(valeur)
625 Cette classe est un validateur qui controle une liste de validateurs
626 Elle verifie qu'au moins un des validateurs de la liste valide la valeur
628 def __init__(self,validators=()):
629 if type(validators) not in (types.ListType,types.TupleType):
630 validators=(validators,)
632 for validator in validators:
633 if type(validator) == types.FunctionType:
634 self.validators.append(FunctionVal(validator))
636 self.validators.append(validator)
640 return "\n ou ".join([v.info() for v in self.validators])
642 def info_erreur_item(self):
644 for v in self.validators:
645 err=v.info_erreur_item()
646 if err != " " : l.append(err)
647 chaine=" \n ou ".join(l)
650 def info_erreur_liste(self):
652 for v in self.validators:
653 err=v.info_erreur_liste()
654 if err != " " : l.append(err)
655 chaine=" \n ou ".join(l)
660 Si plusieurs validateurs sont reliés par un OU
661 il suffit qu'un seul des validateurs attende une liste
662 pour qu'on considère que leur union attend une liste.
664 for validator in self.validators:
665 v=validator.is_list()
670 def verif(self,valeur):
671 for validator in self.validators:
672 v=validator.verif(valeur)
677 def verif_item(self,valeur):
678 for validator in self.validators:
679 v=validator.verif_item(valeur)
684 def verif_cata(self):
686 for validator in self.validators:
687 v=validator.verif_cata()
688 if not v :infos.append(validator.cata_info)
690 self.cata_info="\n".join(infos)
697 Dans le cas ou plusieurs validateurs sont reliés par un OU
698 il faut que tous les validateurs proposent un choix pour
699 qu'on considère que leur union propose un choix.
700 Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix
701 En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un choix (1,2,3,4,5,6)
703 for validator in self.validators:
704 v=validator.has_into()
709 def get_into(self,liste_courante=None,into_courant=None):
711 Dans le cas ou plusieurs validateurs sont reliés par un OU
712 tous les validateurs doivent proposer un choix pour
713 qu'on considère que leur union propose un choix. Tous les choix
714 proposés par les validateurs sont réunis (opérateur d'union).
715 Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix
716 En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un
720 for validator in self.validators:
721 v_into=validator.get_into(liste_courante,into_courant)
724 validator_into.extend(v_into)
725 return validator_into
727 def valide_liste_partielle(self,liste_courante=None):
729 Méthode de validation de liste partielle pour le validateur Or.
730 Si un des validateurs gérés par le validateur Or considère la
731 liste comme valide, le validateur Or la considère comme valide.
733 for validator in self.validators:
734 v=validator.valide_liste_partielle(liste_courante)
741 Cette classe est un validateur qui controle une liste de validateurs
742 Elle verifie que tous les validateurs de la liste valident la valeur
744 def __init__(self,validators=()):
745 if type(validators) not in (types.ListType,types.TupleType):
746 validators=(validators,)
748 for validator in validators:
749 if type(validator) == types.FunctionType:
750 self.validators.append(FunctionVal(validator))
752 self.validators.append(validator)
756 return "\n et ".join([v.info() for v in self.validators])
758 def info_erreur_item(self):
761 for v in self.validators:
762 if v.info_erreur_item() != " " :
764 chaine=v.info_erreur_item()
767 chaine=chaine+" \n et "+v.info_erreur_item()
770 def info_erreur_liste(self):
772 for v in self.validators:
773 if v.info_erreur_liste() != " " :
775 chaine=v.info_erreur_liste()
778 chaine=chaine+" \n et "+v.info_erreur_liste()
781 def verif(self,valeur):
782 for validator in self.validators:
783 v=validator.verif(valeur)
785 self.local_info=validator.info()
789 def verif_item(self,valeur):
790 for validator in self.validators:
791 v=validator.verif_item(valeur)
793 # L'info n'est probablement pas la meme que pour verif ???
794 self.local_info=validator.info()
798 def verif_cata(self):
800 for validator in self.validators:
801 v=validator.verif_cata()
802 if not v :infos.append(validator.cata_info)
804 self.cata_info="\n".join(infos)
809 def valide_liste_partielle(self,liste_courante=None):
811 Méthode de validation de liste partielle pour le validateur And.
812 Tous les validateurs gérés par le validateur And doivent considérer
813 la liste comme valide, pour que le validateur And la considère
816 for validator in self.validators:
817 v=validator.valide_liste_partielle(liste_courante)
824 Si plusieurs validateurs sont reliés par un ET
825 il faut que tous les validateurs attendent une liste
826 pour qu'on considère que leur intersection attende une liste.
827 Exemple Range(2,5) ET Card(1) n'attend pas une liste
828 Range(2,5) ET Pair attend une liste
830 for validator in self.validators:
831 v=validator.is_list()
838 Dans le cas ou plusieurs validateurs sont reliés par un ET
839 il suffit qu'un seul validateur propose un choix pour
840 qu'on considère que leur intersection propose un choix.
841 Exemple : Enum(1,2,3) ET entier pair, propose un choix
842 En revanche, entier pair ET superieur à 10 ne propose pas de choix
844 for validator in self.validators:
845 v=validator.has_into()
850 def get_into(self,liste_courante=None,into_courant=None):
852 Dans le cas ou plusieurs validateurs sont reliés par un ET
853 il suffit qu'un seul validateur propose un choix pour
854 qu'on considère que leur intersection propose un choix. Tous les
855 choix proposés par les validateurs sont croisés (opérateur
857 Exemple : Enum(1,2,3) ET entier pair, propose un choix (2,)
858 En revanche, Enum(1,2,3) ET Enum(4,5,6) ne propose pas de choix.
860 for validator in self.validators:
861 into_courant=validator.get_into(liste_courante,into_courant)
862 if into_courant in ([],None):break
865 def do_liste(validators):
867 Convertit une arborescence de validateurs en OrVal ou AndVal
868 validators est une liste de validateurs ou de listes ou de tuples
871 for validator in validators:
872 if type(validator) == types.FunctionType:
873 valids.append(FunctionVal(validator))
874 elif type(validator) == types.TupleType:
875 valids.append(OrVal(do_liste(validator)))
876 elif type(validator) == types.ListType:
877 valids.append(AndVal(do_liste(validator)))
879 valids.append(validator)
882 def validatorFactory(validator):
883 if type(validator) == types.FunctionType:
884 return FunctionVal(validator)
885 elif type(validator) == types.TupleType:
886 return OrVal(do_liste(validator))
887 elif type(validator) == types.ListType:
888 return AndVal(do_liste(validator))