Salome HOME
mise en cohesion 78
[tools/eficas.git] / Noyau / N_VALIDATOR.py
1 # coding=utf-8
2 # person_in_charge: mathieu.courtois at edf.fr
3 # ======================================================================
4 # COPYRIGHT (C) 1991 - 2015  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.
9 #
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.
14 #
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 # ======================================================================
19
20 """
21    Ce module contient toutes les classes necessaires pour
22    implanter le concept de validateur dans Accas
23 """
24 import types
25 import traceback
26 import re
27 from N_ASSD import ASSD
28 from N_types import is_int, is_float_or_int, is_complex, is_number, is_str, is_sequence
29 from strfunc import convert, ufmt
30
31
32 class ValError(Exception):
33     pass
34
35
36 def cls_mro(cls):
37     if hasattr(cls, "__mro__"):
38         return cls.__mro__
39     mro = [cls]
40     for base in cls.__bases__:
41         mro.extend(cls_mro(base))
42     return mro
43
44
45 class Protocol:
46
47     def __init__(self, name):
48         self.registry = {}
49         self.name = name
50         self.args = {}
51
52     def register(self, T, A):
53         self.registry[T] = A
54
55     def adapt(self, obj):
56         # (a) verifier si l'objet peut s'adapter au protocole
57         adapt = getattr(obj, '__adapt__', None)
58         if adapt is not None:
59             # on demande à l'objet obj de réaliser lui-meme l'adaptation
60             return adapt(self)
61
62         # (b) verifier si un adapteur est enregistré (si oui l'utiliser)
63         if self.registry:
64             for T in cls_mro(obj.__class__):
65                 if T in self.registry:
66                     return self.registry[T](obj, self, **self.args)
67
68         # (c) utiliser l'adapteur par defaut
69         return self.default(obj, **self.args)
70
71     def default(self, obj, **args):
72         raise TypeError("Can't adapt %s to %s" %
73                         (obj.__class__.__name__, self.name))
74
75
76 class PProtocol(Protocol):
77
78     """Verificateur de protocole paramétré (classe de base)"""
79     # Protocole paramétré. Le registre est unique pour toutes les instances.
80     # La methode register est une methode de classe
81     registry = {}
82
83     def __init__(self, name, **args):
84         self.name = name
85         self.args = args
86
87     def register(cls, T, A):
88         cls.registry[T] = A
89     register = classmethod(register)
90
91
92 class ListProtocol(Protocol):
93
94     """Verificateur de protocole liste : convertit un objet quelconque en liste pour validation ultérieure"""
95
96     def default(self, obj):
97         if type(obj) is tuple:
98             if len(obj) > 0 and obj[0] in ('RI', 'MP'):
99                 # il s'agit d'un complexe ancienne mode. La cardinalite vaut 1
100                 return (obj,)
101             else:
102                 return obj
103         elif type(obj) is list:
104             return obj
105         elif obj == None:
106             # pas de valeur affecte. La cardinalite vaut 0
107             return obj
108         elif is_str(obj):
109             # il s'agit d'une chaine. La cardinalite vaut 1
110             return (obj,)
111         else:
112             try:
113                 # si l'objet supporte len, on a la cardinalite
114                 length = len(obj)
115                 return obj
116             except:
117                 # sinon elle vaut 1
118                 return (obj,)
119
120 listProto = ListProtocol("list")
121
122
123 class TypeProtocol(PProtocol):
124
125     """Verificateur de type parmi une liste de types possibles"""
126     # pas de registre par instance. Registre unique pour toutes les instances
127     # de TypeProtocol
128     registry = {}
129
130     def __init__(self, name, typ=None):
131         PProtocol.__init__(self, name, typ=typ)
132         self.typ = typ
133
134     def default(self, obj, typ):
135
136         err = ""
137         for type_permis in typ:
138             if type_permis == 'R':
139                 if is_float_or_int(obj):
140                     return obj
141             elif type_permis == 'I':
142                 if is_int(obj):
143                     return obj
144             elif type_permis == 'C':
145                 if self.is_complexe(obj):
146                     return obj
147             elif type_permis == 'TXM':
148                 if is_str(obj):
149                     return obj
150             elif type_permis == 'shell':
151                 if is_str(obj):
152                     return obj
153             elif type_permis == 'Fichier':
154                 import os
155                 if (len(typ) > 2 and typ[2] == "Sauvegarde") or os.path.isfile(obj):
156                     return obj
157                 else:
158                     raise ValError(
159                         ufmt(_(u"%s n'est pas un fichier valide"), repr(obj)))
160             elif type_permis == 'FichierNoAbs':
161                 import os
162                 if (len(typ) > 2 and typ[2] == "Sauvegarde") or isinstance(obj, type("")):
163                     return obj
164                 else:
165                     raise ValError(
166                         ufmt(_(u"%s n'est pas un fichier valide"), repr(obj)))
167             elif type_permis == 'Repertoire':
168                 import os
169                 if os.path.isdir(obj):
170                     return obj
171                 else:
172                     raise ValError(
173                         ufmt(_(u"%s n'est pas un répertoire valide"), repr(obj)))
174             elif type(type_permis) == types.ClassType or isinstance(type_permis, type):
175                 try:
176                     if self.is_object_from(obj, type_permis):
177                         return obj
178                 except Exception, err:
179                     pass
180             elif type(type_permis) == types.InstanceType or isinstance(type_permis, object):
181                 try:
182                     if type_permis.__convert__(obj):
183                         return obj
184                 except Exception, err:
185                     pass
186             else:
187                 print convert(ufmt(_(u"Type non encore géré %s"), `type_permis`))
188         raise ValError(
189             ufmt(_(u"%s (de type %s) n'est pas d'un type autorisé: %s %s"),
190                  repr(obj), type(obj), typ, unicode(err)))
191
192     def is_complexe(self, valeur):
193         """ Retourne 1 si valeur est un complexe, 0 sinon """
194         if is_number(valeur):
195             # Pour permettre l'utilisation de complexes Python (accepte les
196             # entiers et réels)
197             return 1
198         elif type(valeur) != tuple:
199             # On n'autorise pas les listes pour les complexes
200             return 0
201         elif len(valeur) != 3:
202             return 0
203         else:
204             # Un complexe doit etre un tuple de longueur 3 avec 'RI' ou 'MP' comme premiere
205             # valeur suivie de 2 reels.
206             if valeur[0].strip() in ('RI', 'MP'):
207                 try:
208                     v1 = reelProto.adapt(valeur[1]), reelProto.adapt(valeur[2])
209                     return 1
210                 except:
211                     return 0
212             else:
213                 return 0
214
215     def is_object_from(self, objet, classe):
216         """
217            Retourne 1 si objet est une instance de la classe classe, 0 sinon
218         """
219         convert = getattr(classe, '__convert__', None)
220         if convert is not None:
221             # classe verifie les valeurs
222             try:
223                 v = convert(objet)
224                 return v is not None
225             except ValueError, err:
226                 raise
227             except:
228                 return 0
229         # On accepte les instances de la classe et des classes derivees
230         return isinstance(objet, classe)
231
232 reelProto = TypeProtocol("reel", typ=('R',))
233
234
235 class CardProtocol(PProtocol):
236
237     """Verificateur de cardinalité """
238     # pas de registre par instance. Registre unique pour toutes les instances
239     registry = {}
240
241     def __init__(self, name, min=1, max=1):
242         PProtocol.__init__(self, name, min=min, max=max)
243
244     def default(self, obj, min, max):
245         length = len(obj)
246         if length < min or length > max:
247             raise ValError(
248                 ufmt(
249                     _(u"Nombre d'arguments de %s incorrect (min = %s, max = %s)"),
250                     repr(obj), min, max))
251         return obj
252
253
254 class IntoProtocol(PProtocol):
255
256     """Verificateur de choix possibles : liste discrète ou intervalle"""
257     # pas de registre par instance. Registre unique pour toutes les instances
258     registry = {}
259
260     def __init__(self, name, into=None, val_min='**', val_max='**'):
261         PProtocol.__init__(
262             self, name, into=into, val_min=val_min, val_max=val_max)
263         self.val_min = val_min
264         self.val_max = val_max
265
266     def default(self, obj, into, val_min, val_max):
267         if into:
268             if obj not in into:
269                 raise ValError(
270                     ufmt(
271                         _(u"La valeur : %s  ne fait pas partie des choix possibles %s"),
272                         repr(obj), into))
273         else:
274             # on est dans le cas d'un ensemble continu de valeurs possibles
275             # (intervalle)
276             if is_float_or_int(obj):
277                 if val_min == '**':
278                     val_min = obj - 1
279                 if val_max == '**':
280                     val_max = obj + 1
281                 if obj < val_min or obj > val_max:
282                     raise ValError(
283                         ufmt(
284                             _(u"La valeur : %s est en dehors du domaine de validité [ %s , %s ]"),
285                             repr(obj), self.val_min, self.val_max))
286         return obj
287
288
289 class MinStr:
290     # exemple de classe pour verificateur de type
291     # on utilise des instances de classe comme type (typ=MinStr(3,6), par
292     # exemple)
293
294     def __init__(self, min, max):
295         self.min = min
296         self.max = max
297
298     def __convert__(self, valeur):
299         if is_str(valeur) and self.min <= len(valeur) <= self.max:
300             return valeur
301         raise ValError(
302             ufmt(
303                 _(u"%s n'est pas une chaine de longueur comprise entre %s et %s"),
304                 valeur, self.min, self.max))
305
306     def __repr__(self):
307         return ufmt(_(u"TXM de longueur entre %s et %s"), self.min, self.max)
308
309
310 class Valid(PProtocol):
311
312     """
313          Cette classe est la classe mere des validateurs Accas
314          Elle doit etre derivee
315          Elle presente la signature des methodes indispensables pour son bon
316          fonctionnement et dans certains cas leur comportement par défaut.
317
318          @ivar cata_info: raison de la validite ou de l'invalidite du validateur meme
319          @type cata_info: C{string}
320     """
321     registry = {}
322
323     def __init__(self, **args):
324         PProtocol.__init__(self, "valid", **args)
325
326     def info(self):
327         """
328            Cette methode retourne une chaine de caractères informative sur
329            la validation demandée par le validateur. Elle est utilisée
330            pour produire le compte-rendu de validité du mot clé associé.
331         """
332         return _(u"valeur valide")
333
334     def aide(self):
335         """
336            Cette methode retourne une chaine de caractère qui permet
337            de construire un message d'aide en ligne.
338            En général, le message retourné est le meme que celui retourné par la
339            méthode info.
340         """
341         return self.info()
342
343     def info_erreur_item(self):
344         """
345            Cette méthode permet d'avoir un message d'erreur pour un item
346            dans une liste dans le cas ou le validateur fait des vérifications
347            sur les items d'une liste. Si le validateur fait seulement des
348            vérifications sur la liste elle meme et non sur ses items, la méthode
349            doit retourner une chaine vide.
350         """
351         return " "
352
353     def info_erreur_liste(self):
354         """
355            Cette méthode a un comportement complémentaire de celui de
356            info_erreur_item. Elle retourne un message d'erreur lié uniquement
357            aux vérifications sur la liste elle meme et pas sur ses items.
358            Dans le cas où le validateur ne fait pas de vérification sur des
359            listes, elle retourne une chaine vide
360         """
361         return " "
362
363     def verif(self, valeur):
364         """
365             Cette methode sert a verifier si la valeur passee en argument est consideree
366             comme valide ou non par le validateur. Dans le premier cas le validateur retourne 1
367             (valide) sinon 0 (invalide).
368
369             @type valeur: tout type python
370             @param valeur: valeur du mot cle a valider
371             @rtype: C{boolean}
372             @return: indicateur de validite 1 (valide) ou 0 (invalide)
373         """
374         raise NotImplementedError("Must be implemented")
375
376     def verif_item(self, valeur):
377         """
378            La methode verif du validateur effectue une validation complete de
379            la valeur. valeur peut etre un scalaire ou une liste. Le validateur
380            doit traiter les 2 aspects s'il accepte des listes (dans ce cas la
381            methode is_list doit retourner 1).
382            La methode valid_item sert pour effectuer des validations partielles
383            de liste. Elle doit uniquement verifier la validite d'un item de
384            liste mais pas les caracteristiques de la liste.
385         """
386         return 0
387
388     def valide_liste_partielle(self, liste_courante):
389         """
390            Cette methode retourne un entier qui indique si liste_courante est partiellement valide (valeur 1)
391            ou invalide (valeur 0). La validation partielle concerne les listes en cours de construction : on
392            veut savoir si la liste en construction peut etre complétée ou si elle peut déjà etre considérée
393            comme invalide.
394            En général un validateur effectue la meme validation pour les listes partielles et les
395            listes complètes.
396         """
397         return self.verif(liste_courante)
398
399     def verif_cata(self):
400         """
401             Cette methode sert a realiser des verifications du validateur lui meme.
402             Elle est facultative et retourne 1 (valide) par defaut.
403             Elle retourne 0 si le validateur est lui meme invalide si par exemple ses
404             parametres de definition ne sont pas corrects.
405             La raison de l'invalidite est stockee dans l'attribut cata_info.
406
407             @rtype: C{boolean}
408             @return: indicateur de validite 1 (valide) ou 0 (invalide)
409         """
410         return 1
411
412     def is_list(self):
413         """
414            Cette méthode retourne un entier qui indique si le validateur
415            permet les listes (valeur 1) ou ne les permet pas (valeur 0).
416            Par défaut, un validateur n'autorise que des scalaires.
417         """
418         return 0
419
420     def has_into(self):
421         """
422            Cette méthode retourne un entier qui indique si le validateur
423            propose une liste de choix (valeur 1) ou n'en propose pas.
424            Par défaut, un validateur n'en propose pas.
425         """
426         return 0
427
428     def get_into(self, liste_courante=None, into_courant=None):
429         """
430            Cette méthode retourne la liste de choix proposée par le validateur.
431            Si le validateur ne propose pas de liste de choix, la méthode
432            retourne None.
433            L'argument d'entrée liste_courante, s'il est différent de None, donne
434            la liste des choix déjà effectués par l'utilisateur. Dans ce cas, la
435            méthode get_into doit calculer la liste des choix en en tenant
436            compte. Par exemple, si le validateur n'autorise pas les répétitions,
437            la liste des choix retournée ne doit pas contenir les choix déjà
438            contenus dans liste_courante.
439            L'argument d'entrée into_courant, s'il est différent de None, donne
440            la liste des choix proposés par d'autres validateurs. Dans ce cas,
441            la méthode get_into doit calculer la liste des choix à retourner
442            en se limitant à cette liste initiale. Par exemple, si into_courant
443            vaut (1,2,3) et que le validateur propose la liste de choix (3,4,5),
444            la méthode ne doit retourner que (3,).
445
446            La méthode get_into peut retourner une liste vide [], ce qui veut
447            dire qu'il n'y a pas (ou plus) de choix possible. Cette situation
448            peut etre normale : l''utilisateur a utilisé tous les choix, ou
449            résulter d'une incohérence des validateurs :
450            choix parmi (1,2,3) ET choix parmi (4,5,6). Il est impossible de
451            faire la différence entre ces deux situations.
452         """
453         return into_courant
454
455
456 class ListVal(Valid):
457
458     """
459         Cette classe sert de classe mère pour tous les validateurs qui acceptent
460         des listes.
461     """
462
463     def is_list(self):
464         return 1
465
466     def get_into(self, liste_courante=None, into_courant=None):
467         """
468            Cette méthode get_into effectue un traitement général qui consiste
469            a filtrer la liste de choix into_courant, si elle existe, en ne
470            conservant que les valeurs valides (appel de la méthode valid).
471         """
472         if into_courant is None:
473             return None
474         else:
475             liste_choix = []
476             for e in into_courant:
477                 if self.verif(e):
478                     liste_choix.append(e)
479             return liste_choix
480
481     def convert(self, valeur):
482         """
483            Méthode convert pour les validateurs de listes. Cette méthode
484            fait appel à la méthode convert_item sur chaque élément de la
485            liste.
486         """
487         if is_sequence(valeur):
488             for val in valeur:
489                 self.convert_item(val)
490             return valeur
491         else:
492             return self.convert_item(valeur)
493
494     def verif(self, valeur):
495         """
496            Méthode verif pour les validateurs de listes. Cette méthode
497            fait appel à la méthode verif_item sur chaque élément de la
498            liste. Si valeur est un paramètre, on utilise sa valeur effective
499            valeur.valeur.
500         """
501         if is_sequence(valeur):
502             for val in valeur:
503                 if not self.verif_item(val):
504                     return 0
505             return 1
506         else:
507             return self.verif_item(valeur)
508
509
510 class Compulsory(ListVal):
511     """
512         Validateur operationnel
513         Verification de la présence obligatoire d'un élément dans une liste
514     """
515     registry = {}
516
517     def __init__(self, elem=()):
518         if not is_sequence(elem):
519             elem = (elem,)
520         Valid.__init__(self, elem=elem)
521         self.elem = elem
522         self.cata_info = ""
523
524     def info(self):
525         return ufmt(_(u"valeur %s obligatoire"), `self.elem`)
526
527     def default(self, valeur, elem):
528         return valeur
529
530     def verif_item(self, valeur):
531         return 1
532
533     def convert(self, valeur):
534         elem = list(self.elem)
535         for val in valeur:
536             v = self.adapt(val)
537             if v in elem:
538                 elem.remove(v)
539         if elem:
540             raise ValError(
541                 ufmt(_(u"%s ne contient pas les elements obligatoires : %s "),
542                      valeur, elem))
543         return valeur
544
545     def has_into(self):
546         return 1
547
548     def verif(self, valeur):
549         if not is_sequence(valeur):
550             liste = list(valeur)
551         else:
552             liste = valeur
553         for val in self.elem:
554             if val not in liste:
555                 return 0
556         return 1
557
558     def info_erreur_item(self):
559         return _(u"La valeur n'est pas dans la liste des choix possibles")
560
561
562 class Together(ListVal):
563     """
564         Validateur operationnel
565         si un des éléments est présent les autres doivent aussi l'être
566     """
567     registry = {}
568
569     def __init__(self, elem=()):
570         if not is_sequence(elem):
571             elem = (elem,)
572         Valid.__init__(self, elem=elem)
573         self.elem = elem
574         self.cata_info = ""
575
576     def info(self):
577         return ufmt(_(u"%s présent ensemble"), `self.elem`)
578
579     def default(self, valeur, elem):
580         return valeur
581
582     def verif_item(self, valeur):
583         return 1
584
585     def convert(self, valeur):
586         elem = list(self.elem)
587         for val in valeur:
588             v = self.adapt(val)
589             if v in elem: elem.remove(v)
590         if ( len(elem) == 0 ): return valeur
591         if len(elem) != len(list(self.elem)) :
592             raise ValError( ufmt(_(u"%s ne contient pas les éléments devant être présent ensemble: %s "), valeur, elem))
593         return valeur
594
595     def has_into(self):
596         return 1
597
598     def verif(self, valeur):
599         if not is_sequence(valeur):
600             liste = list(valeur)
601         else:
602             liste = valeur
603         compte = 0
604         for val in self.elem:
605             if val in liste: compte += 1
606         if ( compte == 0 ): return 1
607         if ( compte != len( list(self.elem) ) ): return 0
608         return 1
609
610     def info_erreur_item(self):
611         return _(u"La valeur n'est pas dans la liste des choix possibles")
612
613
614 class Absent(ListVal):
615     """
616         Validateur operationnel
617         si un des éléments est présent non valide
618     """
619     registry = {}
620
621     def __init__(self, elem=()):
622         if not is_sequence(elem):
623             elem = (elem,)
624         Valid.__init__(self, elem=elem)
625         self.elem = elem
626         self.cata_info = ""
627
628     def info(self):
629         return ufmt(_(u"%s absent"), `self.elem`)
630
631     def default(self, valeur, elem):
632         return valeur
633
634     def verif_item(self, valeur):
635         return 1
636
637     def convert(self, valeur):
638         elem = list(self.elem)
639         for val in valeur:
640             v = self.adapt(val)
641             if v in elem:
642                 raise ValError( ufmt(_(u"%s n'est pas autorisé : %s "), v, elem))
643         return valeur
644
645     def has_into(self):
646         return 1
647
648     def verif(self, valeur):
649         if not is_sequence(valeur):
650             liste = list(valeur)
651         else:
652             liste = valeur
653         for val in self.elem:
654             if val in liste: return 0
655         return 1
656
657     def info_erreur_item(self):
658         return _(u"La valeur n'est pas dans la liste des choix possibles")
659
660
661 class NoRepeat(ListVal):
662     """
663         Validateur operationnel
664         Verification d'absence de doublons dans la liste.
665     """
666     def __init__(self):
667         Valid.__init__(self)
668         self.cata_info = ""
669
670     def info(self):
671         return _(u": pas de présence de doublon dans la liste")
672
673     def info_erreur_liste(self):
674         return _(u"Les doublons ne sont pas permis")
675
676     def default(self, valeur):
677         if valeur in self.liste:
678             raise ValError(ufmt(_(u"%s est un doublon"), valeur))
679         return valeur
680
681     def convert(self, valeur):
682         self.liste = []
683         for val in valeur:
684             v = self.adapt(val)
685             self.liste.append(v)
686         return valeur
687
688     def verif_item(self, valeur):
689         return 1
690
691     def verif(self, valeur):
692         if is_sequence(valeur):
693             liste = list(valeur)
694             for val in liste:
695                 if liste.count(val) != 1:
696                     return 0
697             return 1
698         else:
699             return 1
700
701     def get_into(self, liste_courante=None, into_courant=None):
702         """
703         Methode get_into spécifique pour validateur NoRepeat, on retourne
704         une liste de choix qui ne contient aucune valeur de into_courant
705         déjà contenue dans liste_courante
706         """
707         if into_courant is None:
708             liste_choix = None
709         else:
710             liste_choix = []
711             for e in into_courant:
712                 if e in liste_choix:
713                     continue
714                 if liste_courante is not None and e in liste_courante:
715                     continue
716                 liste_choix.append(e)
717         return liste_choix
718
719
720 class LongStr(ListVal):
721
722     """
723         Validateur operationnel
724         Verification de la longueur d une chaine
725     """
726
727     def __init__(self, low, high):
728         ListVal.__init__(self, low=low, high=high)
729         self.low = low
730         self.high = high
731         self.cata_info = ""
732
733     def info(self):
734         return ufmt(_(u"longueur de la chaine entre %s et %s"), self.low, self.high)
735
736     def info_erreur_item(self):
737         return _(u"Longueur de la chaine incorrecte")
738
739     def convert(self, valeur):
740         for val in valeur:
741             v = self.adapt(val)
742         return valeur
743
744     def verif_item(self, valeur):
745         try:
746             self.adapt(valeur)
747             return 1
748         except:
749             return 0
750
751     def default(self, valeur, low, high):
752         if not is_str(valeur):
753             raise ValError(ufmt(_(u"%s n'est pas une chaine"), repr(valeur)))
754         if valeur[0] == "'" and valeur[-1] == "'":
755             low = low + 2
756             high = high + 2
757         if len(valeur) < low or len(valeur) > high:
758             raise ValError(
759                 ufmt(_(u"%s n'est pas de la bonne longueur"), repr(valeur)))
760         return valeur
761
762
763 class OnlyStr(ListVal):
764
765     """
766         Validateur operationnel
767         Valide que c'est une chaine
768     """
769
770     def __init__(self):
771         ListVal.__init__(self)
772         self.cata_info = ""
773
774     def info(self):
775         return _(u"regarde si c'est une chaine")
776
777     def info_erreur_item(self):
778         return _(u"Ce n'est pas une chaine")
779
780     def convert(self, valeur):
781         for val in valeur:
782             v = self.adapt(val)
783         return valeur
784
785     def verif_item(self, valeur):
786         try:
787             self.adapt(valeur)
788             return 1
789         except:
790             return 0
791
792     def default(self, valeur):
793         if not is_str(valeur):
794             raise ValError(ufmt(_(u"%s n'est pas une chaine"), repr(valeur)))
795         return valeur
796
797
798 class OrdList(ListVal):
799
800     """
801         Validateur operationnel
802         Verification qu'une liste est croissante ou decroissante
803     """
804
805     def __init__(self, ord):
806         ListVal.__init__(self, ord=ord)
807         self.ord = ord
808         self.cata_info = ""
809
810     def info(self):
811         return ufmt(_(u"liste %s"), self.ord)
812
813     def info_erreur_liste(self):
814         return ufmt(_(u"La liste doit etre en ordre %s"), self.ord)
815
816     def convert(self, valeur):
817         self.val = None
818         self.liste = valeur
819         for v in valeur:
820             self.adapt(v)
821         return valeur
822
823     def default(self, valeur, ord):
824         if self.ord == 'croissant':
825             if self.val is not None and valeur < self.val:
826                 raise ValError(
827                     ufmt(_(u"%s n'est pas par valeurs croissantes"), repr(self.liste)))
828         elif self.ord == 'decroissant':
829             if self.val is not None and valeur > self.val:
830                 raise ValError(
831                     ufmt(_(u"%s n'est pas par valeurs decroissantes"), repr(self.liste)))
832         self.val = valeur
833         return valeur
834
835     def verif_item(self, valeur):
836         return 1
837
838     def get_into(self, liste_courante=None, into_courant=None):
839         """
840         Methode get_into spécifique pour validateur OrdList, on retourne
841         une liste de choix qui ne contient aucune valeur de into_courant
842         dont la valeur est inférieure à la dernière valeur de
843         liste_courante, si elle est différente de None.
844         """
845         if into_courant is None:
846             return None
847         elif not liste_courante:
848             return into_courant
849         else:
850             liste_choix = []
851             last_val = liste_choix[-1]
852             for e in into_courant:
853                 if self.ord == 'croissant' and e <= last_val:
854                     continue
855                 if self.ord == 'decroissant' and e >= last_val:
856                     continue
857                 liste_choix.append(e)
858             return liste_choix
859
860
861 class OrVal(Valid):
862
863     """
864         Validateur operationnel
865         Cette classe est un validateur qui controle une liste de validateurs
866         Elle verifie qu'au moins un des validateurs de la liste valide la valeur
867     """
868
869     def __init__(self, validators=()):
870         if not is_sequence(validators):
871             validators = (validators,)
872         self.validators = []
873         for validator in validators:
874             if type(validator) == types.FunctionType:
875                 self.validators.append(FunctionVal(validator))
876             else:
877                 self.validators.append(validator)
878         self.cata_info = ""
879
880     def info(self):
881         return "\n ou ".join([v.info() for v in self.validators])
882
883     def convert(self, valeur):
884         for validator in self.validators:
885             try:
886                 return validator.convert(valeur)
887             except:
888                 pass
889         raise ValError(ufmt(_(u"%s n'est pas du bon type"), repr(valeur)))
890
891     def info_erreur_item(self):
892         l = []
893         for v in self.validators:
894             err = v.info_erreur_item()
895             if err != " ":
896                 l.append(err)
897         chaine = " \n ou ".join(l)
898         return chaine
899
900     def info_erreur_liste(self):
901         l = []
902         for v in self.validators:
903             err = v.info_erreur_liste()
904             if err != " ":
905                 l.append(err)
906         chaine = " \n ou ".join(l)
907         return chaine
908
909     def is_list(self):
910         """
911            Si plusieurs validateurs sont reliés par un OU
912            il suffit qu'un seul des validateurs attende une liste
913            pour qu'on considère que leur union attend une liste.
914         """
915         for validator in self.validators:
916             v = validator.is_list()
917             if v:
918                 return 1
919         return 0
920
921     def verif(self, valeur):
922         for validator in self.validators:
923             v = validator.verif(valeur)
924             if v:
925                 return 1
926         return 0
927
928     def verif_item(self, valeur):
929         for validator in self.validators:
930             v = validator.verif_item(valeur)
931             if v:
932                 return 1
933         return 0
934
935     def verif_cata(self):
936         infos = []
937         for validator in self.validators:
938             v = validator.verif_cata()
939             if not v:
940                 infos.append(validator.cata_info)
941         if infos:
942             self.cata_info = "\n".join(infos)
943             return 0
944         self.cata_info = ""
945         return 1
946
947     def has_into(self):
948         """
949         Dans le cas ou plusieurs validateurs sont reliés par un OU
950         il faut que tous les validateurs proposent un choix pour
951         qu'on considère que leur union propose un choix.
952         Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix
953         En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un choix (1,2,3,4,5,6)
954         """
955         for validator in self.validators:
956             v = validator.has_into()
957             if not v:
958                 return 0
959         return 1
960
961     def get_into(self, liste_courante=None, into_courant=None):
962         """
963         Dans le cas ou plusieurs validateurs sont reliés par un OU
964         tous les validateurs doivent proposer un choix pour
965         qu'on considère que leur union propose un choix. Tous les choix
966         proposés par les validateurs sont réunis (opérateur d'union).
967         Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix
968         En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un
969         choix (1,2,3,4,5,6)
970         """
971         validator_into = []
972         for validator in self.validators:
973             v_into = validator.get_into(liste_courante, into_courant)
974             if v_into is None:
975                 return v_into
976             validator_into.extend(v_into)
977         return validator_into
978
979     def valide_liste_partielle(self, liste_courante=None):
980         """
981          Méthode de validation de liste partielle pour le validateur Or.
982          Si un des validateurs gérés par le validateur Or considère la
983          liste comme valide, le validateur Or la considère comme valide.
984         """
985         for validator in self.validators:
986             v = validator.valide_liste_partielle(liste_courante)
987             if v:
988                 return 1
989         return 0
990
991
992 class AndVal(Valid):
993
994     """
995         Validateur operationnel
996         Cette classe est un validateur qui controle une liste de validateurs
997         Elle verifie que tous les validateurs de la liste valident la valeur
998     """
999
1000     def __init__(self, validators=()):
1001         if not is_sequence(validators):
1002             validators = (validators,)
1003         self.validators = []
1004         for validator in validators:
1005             if type(validator) == types.FunctionType:
1006                 self.validators.append(FunctionVal(validator))
1007             else:
1008                 self.validators.append(validator)
1009             if hasattr(validator, 'fonctions'):
1010                 for fonction in validator.fonctions:
1011                     f = getattr(validator, fonction)
1012                     setattr(self, fonction, f)
1013         self.cata_info = ""
1014
1015     def info(self):
1016         return "\n et ".join([v.info() for v in self.validators])
1017
1018     def convert(self, valeur):
1019         for validator in self.validators:
1020             valeur = validator.convert(valeur)
1021         return valeur
1022
1023     def info_erreur_item(self):
1024         chaine = ""
1025         a = 1
1026         for v in self.validators:
1027             if v.info_erreur_item() != " ":
1028                 if a == 1:
1029                     chaine = v.info_erreur_item()
1030                     a = 0
1031                 else:
1032                     chaine = chaine + " \n et " + v.info_erreur_item()
1033         return chaine
1034
1035     def info_erreur_liste(self):
1036         a = 1
1037         for v in self.validators:
1038             if v.info_erreur_liste() != " ":
1039                 if a == 1:
1040                     chaine = v.info_erreur_liste()
1041                     a = 0
1042                 else:
1043                     chaine = chaine + " \n et " + v.info_erreur_liste()
1044         return chaine
1045
1046     def verif(self, valeur):
1047         for validator in self.validators:
1048             v = validator.verif(valeur)
1049             if not v:
1050                 self.local_info = validator.info()
1051                 return 0
1052         return 1
1053
1054     def verif_item(self, valeur):
1055         for validator in self.validators:
1056             v = validator.verif_item(valeur)
1057             if not v:
1058                 # L'info n'est probablement pas la meme que pour verif ???
1059                 self.local_info = validator.info()
1060                 return 0
1061         return 1
1062
1063     def verif_cata(self):
1064         infos = []
1065         for validator in self.validators:
1066             v = validator.verif_cata()
1067             if not v:
1068                 infos.append(validator.cata_info)
1069         if infos:
1070             self.cata_info = "\n".join(infos)
1071             return 0
1072         self.cata_info = ""
1073         return 1
1074
1075     def valide_liste_partielle(self, liste_courante=None):
1076         """
1077          Méthode de validation de liste partielle pour le validateur And.
1078          Tous les validateurs gérés par le validateur And doivent considérer
1079          la liste comme valide, pour que le validateur And la considère
1080          comme valide.
1081         """
1082         for validator in self.validators:
1083             v = validator.valide_liste_partielle(liste_courante)
1084             if not v:
1085                 return 0
1086         return 1
1087
1088     def is_list(self):
1089         """
1090         Si plusieurs validateurs sont reliés par un ET
1091         il faut que tous les validateurs attendent une liste
1092         pour qu'on considère que leur intersection attende une liste.
1093         Exemple Range(2,5) ET Card(1) n'attend pas une liste
1094         Range(2,5) ET Pair attend une liste
1095         """
1096         for validator in self.validators:
1097             v = validator.is_list()
1098             if v == 0:
1099                 return 0
1100         return 1
1101
1102     def has_into(self):
1103         """
1104         Dans le cas ou plusieurs validateurs sont reliés par un ET
1105         il suffit qu'un seul validateur propose un choix pour
1106         qu'on considère que leur intersection propose un choix.
1107         Exemple : Enum(1,2,3) ET entier pair, propose un choix
1108         En revanche, entier pair ET superieur à 10 ne propose pas de choix
1109         """
1110         for validator in self.validators:
1111             v = validator.has_into()
1112             if v:
1113                 return 1
1114         return 0
1115
1116     def get_into(self, liste_courante=None, into_courant=None):
1117         """
1118         Dans le cas ou plusieurs validateurs sont reliés par un ET
1119         il suffit qu'un seul validateur propose un choix pour
1120         qu'on considère que leur intersection propose un choix. Tous les
1121         choix proposés par les validateurs sont croisés (opérateur
1122         d'intersection)
1123         Exemple : Enum(1,2,3) ET entier pair, propose un choix (2,)
1124         En revanche, Enum(1,2,3) ET Enum(4,5,6) ne propose pas de choix.
1125         """
1126         for validator in self.validators:
1127             into_courant = validator.get_into(liste_courante, into_courant)
1128             if into_courant in ([], None):
1129                 break
1130         return into_courant
1131
1132
1133 def do_liste(validators):
1134     """
1135        Convertit une arborescence de validateurs en OrVal ou AndVal
1136        validators est une liste de validateurs ou de listes ou de tuples
1137     """
1138     valids = []
1139     for validator in validators:
1140         if type(validator) == types.FunctionType:
1141             valids.append(FunctionVal(validator))
1142         elif type(validator) is tuple:
1143             valids.append(OrVal(do_liste(validator)))
1144         elif type(validator) is list:
1145             valids.append(AndVal(do_liste(validator)))
1146         else:
1147             valids.append(validator)
1148     return valids
1149
1150
1151 def validatorFactory(validator):
1152     if type(validator) == types.FunctionType:
1153         return FunctionVal(validator)
1154     elif type(validator) is tuple:
1155         return OrVal(do_liste(validator))
1156     elif type(validator) is list:
1157         return AndVal(do_liste(validator))
1158     else:
1159         return validator
1160
1161 # Ci-dessous : exemples de validateur (peu testés)
1162
1163
1164 class RangeVal(ListVal):
1165
1166     """
1167         Exemple de classe validateur : verification qu'une valeur
1168         est dans un intervalle.
1169         Pour une liste on verifie que tous les elements sont
1170         dans l'intervalle
1171         Susceptible de remplacer les attributs "vale_min" "vale_max"
1172         dans les catalogues
1173     """
1174
1175     def __init__(self, low, high):
1176         self.low = low
1177         self.high = high
1178         self.cata_info = ufmt(_(u"%s doit être inférieur a %s"), low, high)
1179
1180     def info(self):
1181         return ufmt(_(u"valeur dans l'intervalle %s , %s"), self.low, self.high)
1182
1183     def convert_item(self, valeur):
1184         if valeur > self.low and valeur < self.high:
1185             return valeur
1186         raise ValError(ufmt(_(u"%s devrait être comprise entre %s et %s"),
1187                             valeur, self.low, self.high))
1188
1189     def verif_item(self, valeur):
1190         return valeur > self.low and valeur < self.high
1191
1192     def info_erreur_item(self):
1193         return ufmt(_(u"La valeur doit etre comprise entre %s et %s"), self.low, self.high)
1194
1195     def verif_cata(self):
1196         if self.low > self.high:
1197             return 0
1198         return 1
1199
1200
1201 class CardVal(Valid):
1202
1203     """
1204         Exemple de classe validateur : verification qu'une liste est
1205         d'une longueur superieur a un minimum (min) et inferieure
1206         a un maximum (max).
1207         Susceptible de remplacer les attributs "min" "max" dans les
1208         catalogues
1209     """
1210
1211     def __init__(self, min='**', max='**'):
1212         self.min = min
1213         self.max = max
1214         self.cata_info = ufmt(_(u"%s doit etre inferieur a %s"), min, max)
1215
1216     def info(self):
1217         return ufmt(_(u"longueur de liste comprise entre  %s et %s"), self.min, self.max)
1218
1219     def info_erreur_liste(self):
1220         return ufmt(
1221             _(u"Le cardinal de la liste doit etre compris entre %s et %s"),
1222             self.min, self.max)
1223
1224     def is_list(self):
1225         return self.max == '**' or self.max > 1
1226
1227     def get_into(self, liste_courante=None, into_courant=None):
1228         if into_courant is None:
1229             return None
1230         elif liste_courante is None:
1231             return into_courant
1232         elif self.max == '**':
1233             return into_courant
1234         elif len(liste_courante) < self.max:
1235             return into_courant
1236         else:
1237             return []
1238
1239     def convert(self, valeur):
1240         if is_sequence(valeur):
1241             l = len(valeur)
1242         elif valeur is None:
1243             l = 0
1244         else:
1245             l = 1
1246         if self.max != '**' and l > self.max:
1247             raise ValError(
1248                 ufmt(_(u"%s devrait etre de longueur inferieure a %s"), valeur, self.max))
1249         if self.min != '**' and l < self.min:
1250             raise ValError(
1251                 ufmt(_(u"%s devrait etre de longueur superieure a %s"), valeur, self.min))
1252         return valeur
1253
1254     def verif_item(self, valeur):
1255         return 1
1256
1257     def verif(self, valeur):
1258         if is_sequence(valeur):
1259             if self.max != '**' and len(valeur) > self.max:
1260                 return 0
1261             if self.min != '**' and len(valeur) < self.min:
1262                 return 0
1263             return 1
1264         else:
1265             if self.max != '**' and 1 > self.max:
1266                 return 0
1267             if self.min != '**' and 1 < self.min:
1268                 return 0
1269             return 1
1270
1271     def verif_cata(self):
1272         if self.min != '**' and self.max != '**' and self.min > self.max:
1273             return 0
1274         return 1
1275
1276     def valide_liste_partielle(self, liste_courante=None):
1277         validite = 1
1278         if liste_courante != None:
1279             if len(liste_courante) > self.max:
1280                 validite = 0
1281         return validite
1282
1283
1284 class PairVal(ListVal):
1285
1286     """
1287         Exemple de classe validateur : verification qu'une valeur
1288         est paire.
1289         Pour une liste on verifie que tous les elements sont
1290         pairs
1291     """
1292
1293     def __init__(self):
1294         ListVal.__init__(self)
1295         self.cata_info = ""
1296
1297     def info(self):
1298         return _(u"valeur paire")
1299
1300     def info_erreur_item(self):
1301         return _(u"La valeur saisie doit etre paire")
1302
1303     def convert(self, valeur):
1304         for val in valeur:
1305             v = self.adapt(val)
1306             if v % 2 != 0:
1307                 raise ValError(
1308                     ufmt(_(u"%s contient des valeurs non paires"), repr(valeur)))
1309         return valeur
1310
1311     def default(self, valeur):
1312         return valeur
1313
1314     def verif_item(self, valeur):
1315         if type(valeur) not in (int, long):
1316             return 0
1317         return valeur % 2 == 0
1318
1319     def verif(self, valeur):
1320         if is_sequence(valeur):
1321             for val in valeur:
1322                 if val % 2 != 0:
1323                     return 0
1324             return 1
1325         else:
1326             if valeur % 2 != 0:
1327                 return 0
1328             return 1
1329
1330
1331 class EnumVal(ListVal):
1332
1333     """
1334         Exemple de classe validateur : verification qu'une valeur
1335         est prise dans une liste de valeurs.
1336         Susceptible de remplacer l attribut "into" dans les catalogues
1337     """
1338
1339     def __init__(self, into=()):
1340         if not is_sequence(into):
1341             into = (into,)
1342         self.into = into
1343         self.cata_info = ""
1344
1345     def info(self):
1346         return "valeur dans %s" % `self.into`
1347
1348     def convert_item(self, valeur):
1349         if valeur in self.into:
1350             return valeur
1351         raise ValError(
1352             ufmt(_(u"%s contient des valeurs hors des choix possibles: %s "),
1353                  valeur, self.into))
1354
1355     def verif_item(self, valeur):
1356         if valeur not in self.into:
1357             return 0
1358         return 1
1359
1360     def has_into(self):
1361         return 1
1362
1363     def get_into(self, liste_courante=None, into_courant=None):
1364         if into_courant is None:
1365             liste_choix = list(self.into)
1366         else:
1367             liste_choix = []
1368             for e in into_courant:
1369                 if e in self.into:
1370                     liste_choix.append(e)
1371         return liste_choix
1372
1373     def info_erreur_item(self):
1374         return _(u"La valeur n'est pas dans la liste des choix possibles")
1375
1376
1377 def ImpairVal(valeur):
1378     """
1379           Exemple de validateur
1380         Cette fonction est un validateur. Elle verifie que la valeur passee
1381         est bien un nombre impair.
1382     """
1383     if is_sequence(valeur):
1384         for val in valeur:
1385             if val % 2 != 1:
1386                 return 0
1387         return 1
1388     else:
1389         if valeur % 2 != 1:
1390             return 0
1391         return 1
1392
1393 ImpairVal.info = "valeur impaire"
1394
1395
1396 class F1Val(Valid):
1397
1398     """
1399         Exemple de validateur
1400         Cette classe est un validateur de dictionnaire (mot cle facteur ?). Elle verifie
1401         que la somme des cles A et B vaut une valeur donnee
1402         en parametre du validateur
1403     """
1404
1405     def __init__(self, somme=10):
1406         self.somme = somme
1407         self.cata_info = ""
1408
1409     def info(self):
1410         return ufmt(_(u"valeur %s pour la somme des cles A et B "), self.somme)
1411
1412     def verif(self, valeur):
1413         if is_sequence(valeur):
1414             for val in valeur:
1415                 if not val.has_key("A"):
1416                     return 0
1417                 if not val.has_key("B"):
1418                     return 0
1419                 if val["A"] + val["B"] != self.somme:
1420                     return 0
1421             return 1
1422         else:
1423             if not valeur.has_key("A"):
1424                 return 0
1425             if not valeur.has_key("B"):
1426                 return 0
1427             if valeur["A"] + valeur["B"] != self.somme:
1428                 return 0
1429             return 1
1430
1431
1432 class FunctionVal(Valid):
1433
1434     """
1435         Exemple de validateur
1436         Cette classe est un validateur qui est initialise avec une fonction
1437     """
1438
1439     def __init__(self, function):
1440         self.function = function
1441
1442     def info(self):
1443         return self.function.info
1444
1445     def verif(self, valeur):
1446         return self.function(valeur)
1447
1448     def verif_item(self, valeur):
1449         return self.function(valeur)
1450
1451     def convert(self, valeur):
1452         return valeur
1453
1454 # MC ca ne devrait plus servir !
1455 CoercableFuncs = {types.IntType:     int,
1456                   types.LongType:    long,
1457                   types.FloatType:   float,
1458                   types.ComplexType: complex,
1459                   types.UnicodeType: unicode}
1460
1461
1462 class TypeVal(ListVal):
1463
1464     """
1465         Exemple de validateur
1466         Cette classe est un validateur qui controle qu'une valeur
1467         est bien du type Python attendu.
1468         Pour une liste on verifie que tous les elements sont du bon type.
1469         Semblable a InstanceVal mais ici on fait le test par tentative de conversion
1470         alors qu'avec InstanceVal on ne teste que si isinstance est vrai.
1471     """
1472
1473     def __init__(self, aType):
1474         # Si aType n'est pas un type, on le retrouve a l'aide de la fonction type
1475         # type(1) == int;type(0.2)==float;etc.
1476         if type(aType) != types.TypeType:
1477             aType = type(aType)
1478         self.aType = aType
1479         try:
1480             self.coerce = CoercableFuncs[aType]
1481         except:
1482             self.coerce = self.identity
1483
1484     def info(self):
1485         return ufmt(_(u"valeur de %s"), self.aType)
1486
1487     def identity(self, value):
1488         if type(value) == self.aType:
1489             return value
1490         raise ValError
1491
1492     def convert_item(self, valeur):
1493         return self.coerce(valeur)
1494
1495     def verif_item(self, valeur):
1496         try:
1497             self.coerce(valeur)
1498         except:
1499             return 0
1500         return 1
1501
1502
1503 class InstanceVal(ListVal):
1504
1505     """
1506         Exemple de validateur
1507         Cette classe est un validateur qui controle qu'une valeur est
1508         bien une instance (au sens Python) d'une classe
1509         Pour une liste on verifie chaque element de la liste
1510     """
1511
1512     def __init__(self, aClass):
1513         # Si aClass est une classe on la memorise dans self.aClass
1514         # sinon c'est une instance dont on memorise la classe
1515         if type(aClass) == types.InstanceType:
1516             # instance ancienne mode
1517             aClass = aClass.__class__
1518         elif type(aClass) == types.ClassType:
1519             # classe ancienne mode
1520             aClass = aClass
1521         elif type(aClass) == type:
1522             # classe nouvelle mode
1523             aClass = aClass
1524         elif isinstance(aClass, object):
1525             # instance nouvelle mode
1526             aClass = type(aClass)
1527         else:
1528             raise ValError(_(u"type non supporté"))
1529
1530         self.aClass = aClass
1531
1532     def info(self):
1533         return ufmt(_(u"valeur d'instance de %s"), self.aClass.__name__)
1534
1535     def verif_item(self, valeur):
1536         if not isinstance(valeur, self.aClass):
1537             return 0
1538         return 1
1539
1540
1541 class VerifTypeTuple(Valid, ListVal):
1542
1543     def __init__(self, typeDesTuples):
1544         self.typeDesTuples = typeDesTuples
1545         Valid.__init__(self)
1546         self.cata_info = ""
1547
1548     def info(self):
1549         return _(u": vérifie les types dans un tuple")
1550
1551     def info_erreur_liste(self):
1552         return _(u"Les types entrés ne sont pas permis")
1553
1554     def default(self, valeur):
1555         # if valeur in self.liste : raise ValError("%s est un doublon" %
1556         # valeur)
1557         return valeur
1558
1559     def is_list(self):
1560         return 1
1561
1562     def convert_item(self, valeur):
1563         if len(valeur) != len(self.typeDesTuples):
1564             raise ValError(
1565                 ufmt(_(u"%s devrait etre de type  %s "), valeur, self.typeDesTuples))
1566         for i in range(len(valeur)):
1567             ok = self.verifType(valeur[i], self.typeDesTuples[i])
1568             if ok != 1:
1569                 raise ValError(
1570                     ufmt(_(u"%s devrait etre de type  %s "), valeur, self.typeDesTuples))
1571         return valeur
1572
1573     def verif_item(self, valeur):
1574         try:
1575             if len(valeur) != len(self.typeDesTuples):
1576                 return 0
1577             for i in range(len(valeur)):
1578                 ok = self.verifType(valeur[i], self.typeDesTuples[i])
1579                 if ok != 1:
1580                     return 0
1581         except:
1582             return 0
1583         return 1
1584
1585     def verifType(self, valeur, type_permis):
1586         if type_permis == 'R':
1587             if type(valeur) in (types.IntType, types.FloatType, types.LongType):
1588                 return 1
1589         elif type_permis == 'I':
1590             if type(valeur) in (types.IntType, types.LongType):
1591                 return 1
1592         elif type_permis == 'C':
1593             if self.is_complexe(valeur):
1594                 return 1
1595         elif type_permis == 'TXM':
1596             if type(valeur) == types.StringType:
1597                 return 1
1598         return 0
1599
1600     def verif(self, valeur):
1601         if type(valeur) in (types.ListType, types.TupleType):
1602             liste = list(valeur)
1603             for val in liste:
1604                 if self.verif_item(val) != 1:
1605                     return 0
1606             return 1
1607
1608
1609 class VerifExiste(ListVal):
1610
1611     """
1612        fonctionne avec into
1613        Met une liste à jour selon les mot clefs existant
1614        exemple si into = ("A","B","C")
1615        si au niveau N du JDC les objets "A" et "C" existe
1616        alors la liste des into deviendra ( "A","C")
1617
1618        niveauVerif est le niveau du JDC dans lequel va s effectuer la verification
1619        niveauVerif est defini par rapport au Noeud :
1620        exemple niveauVerif = 1 : on verifie les freres
1621                niveauVerif = 2 : on verifie les oncles..
1622     """
1623
1624     def __init__(self, niveauVerif):
1625         ListVal.__init__(self)
1626         self.niveauVerif = niveauVerif
1627         self.MCSimp = None
1628         self.listeDesFreres = ()
1629         self.fonctions = ('verifie_liste', 'set_MCSimp')
1630
1631     def is_list(self):
1632         return 1
1633
1634     def verifie_liste(self, liste):
1635         self.set_MCSimp(self.MCSimp)
1636         for item in liste:
1637             if not(item in self.listeDesFreres):
1638                 return 0
1639         return 1
1640
1641     def verif_item(self, valeur):
1642         self.set_MCSimp(self.MCSimp)
1643         if valeur in self.listeDesFreres:
1644             return 1
1645         return 0
1646
1647     def set_MCSimp(self, MCSimp):
1648         self.MCSimp = MCSimp
1649         k = self.niveauVerif
1650         mc = MCSimp
1651         while (k != 0):
1652             parent = mc.parent
1653             mc = parent
1654             k = k - 1
1655         # on met la liste à jour
1656         parent.forceRecalcul = self.niveauVerif
1657         self.listeDesFreres = parent.liste_mc_presents()
1658
1659     def convert_item(self, valeur):
1660         if valeur in self.listeDesFreres:
1661             return valeur
1662         raise ValError(
1663             ufmt(_(u"%s n'est pas dans %s"), valeur, self.listeDesFreres))
1664
1665
1666 class RegExpVal(ListVal):
1667
1668     """
1669     Vérifie qu'une chaîne de caractère corresponde à l'expression régulière 'pattern'
1670     """
1671
1672     errormsg = u'La chaîne "%(value)s" ne correspond pas au motif "%(pattern)s"'
1673
1674     def __init__(self, pattern):
1675         self.pattern = pattern
1676         self.compiled_regexp = re.compile(pattern)
1677
1678     def info(self):
1679         return u'Une chaîne correspondant au motif "%s" est attendue.' % self.pattern
1680
1681     def verif_item(self, valeur):
1682         if self.compiled_regexp.match(valeur):
1683             return 1
1684         else:
1685             return (0, self.errormsg % {"value": valeur, "pattern": self.pattern})
1686
1687     def convert_item(self, valeur):
1688         if self.compiled_regexp.match(valeur):
1689             return valeur
1690         else:
1691             raise ValError(self.errormsg %
1692                            {"value": valeur, "pattern": self.pattern})
1693
1694
1695 class FileExtVal(RegExpVal):
1696
1697     """
1698     Vérifie qu'une chaîne de caractère soit un nom de fichier valide avec l'extension 'ext'
1699     """
1700
1701     def __init__(self, ext):
1702         self.ext = ext
1703         self.errormsg = u'"%%(value)s" n\'est pas un nom de fichier %(ext)s valide' % {
1704             "ext": ext}
1705         #RegExpVal.__init__(self, "^[\w\-]+\.%s$" % self.ext)
1706         #PNPN Modif pour Adao
1707         #RegExpVal.__init__(self, "^[\S]+\.%s$" % self.ext
1708         RegExpVal.__init__(self, "^\S+\.%s$" % self.ext)
1709
1710
1711     def info(self):
1712         return u'Un nom de fichier se terminant par ".%s" est attendu.' % self.ext