Salome HOME
gestion des listes et label sur 2
[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         chaine=""
1038         for v in self.validators:
1039             if v.info_erreur_liste() != " ":
1040                 if a == 1:
1041                     chaine = v.info_erreur_liste()
1042                     a = 0
1043                 else:
1044                     chaine = chaine + " \n et " + v.info_erreur_liste()
1045         return chaine
1046
1047     def verif(self, valeur):
1048         for validator in self.validators:
1049             v = validator.verif(valeur)
1050             if not v:
1051                 self.local_info = validator.info()
1052                 return 0
1053         return 1
1054
1055     def verif_item(self, valeur):
1056         for validator in self.validators:
1057             v = validator.verif_item(valeur)
1058             if not v:
1059                 # L'info n'est probablement pas la meme que pour verif ???
1060                 self.local_info = validator.info()
1061                 return 0
1062         return 1
1063
1064     def verif_cata(self):
1065         infos = []
1066         for validator in self.validators:
1067             v = validator.verif_cata()
1068             if not v:
1069                 infos.append(validator.cata_info)
1070         if infos:
1071             self.cata_info = "\n".join(infos)
1072             return 0
1073         self.cata_info = ""
1074         return 1
1075
1076     def valide_liste_partielle(self, liste_courante=None):
1077         """
1078          Méthode de validation de liste partielle pour le validateur And.
1079          Tous les validateurs gérés par le validateur And doivent considérer
1080          la liste comme valide, pour que le validateur And la considère
1081          comme valide.
1082         """
1083         for validator in self.validators:
1084             v = validator.valide_liste_partielle(liste_courante)
1085             if not v:
1086                 return 0
1087         return 1
1088
1089     def is_list(self):
1090         """
1091         Si plusieurs validateurs sont reliés par un ET
1092         il faut que tous les validateurs attendent une liste
1093         pour qu'on considère que leur intersection attende une liste.
1094         Exemple Range(2,5) ET Card(1) n'attend pas une liste
1095         Range(2,5) ET Pair attend une liste
1096         """
1097         for validator in self.validators:
1098             v = validator.is_list()
1099             if v == 0:
1100                 return 0
1101         return 1
1102
1103     def has_into(self):
1104         """
1105         Dans le cas ou plusieurs validateurs sont reliés par un ET
1106         il suffit qu'un seul validateur propose un choix pour
1107         qu'on considère que leur intersection propose un choix.
1108         Exemple : Enum(1,2,3) ET entier pair, propose un choix
1109         En revanche, entier pair ET superieur à 10 ne propose pas de choix
1110         """
1111         for validator in self.validators:
1112             v = validator.has_into()
1113             if v:
1114                 return 1
1115         return 0
1116
1117     def get_into(self, liste_courante=None, into_courant=None):
1118         """
1119         Dans le cas ou plusieurs validateurs sont reliés par un ET
1120         il suffit qu'un seul validateur propose un choix pour
1121         qu'on considère que leur intersection propose un choix. Tous les
1122         choix proposés par les validateurs sont croisés (opérateur
1123         d'intersection)
1124         Exemple : Enum(1,2,3) ET entier pair, propose un choix (2,)
1125         En revanche, Enum(1,2,3) ET Enum(4,5,6) ne propose pas de choix.
1126         """
1127         for validator in self.validators:
1128             into_courant = validator.get_into(liste_courante, into_courant)
1129             if into_courant in ([], None):
1130                 break
1131         return into_courant
1132
1133
1134 def do_liste(validators):
1135     """
1136        Convertit une arborescence de validateurs en OrVal ou AndVal
1137        validators est une liste de validateurs ou de listes ou de tuples
1138     """
1139     valids = []
1140     for validator in validators:
1141         if type(validator) == types.FunctionType:
1142             valids.append(FunctionVal(validator))
1143         elif type(validator) is tuple:
1144             valids.append(OrVal(do_liste(validator)))
1145         elif type(validator) is list:
1146             valids.append(AndVal(do_liste(validator)))
1147         else:
1148             valids.append(validator)
1149     return valids
1150
1151
1152 def validatorFactory(validator):
1153     if type(validator) == types.FunctionType:
1154         return FunctionVal(validator)
1155     elif type(validator) is tuple:
1156         return OrVal(do_liste(validator))
1157     elif type(validator) is list:
1158         return AndVal(do_liste(validator))
1159     else:
1160         return validator
1161
1162 # Ci-dessous : exemples de validateur (peu testés)
1163
1164
1165 class RangeVal(ListVal):
1166
1167     """
1168         Exemple de classe validateur : verification qu'une valeur
1169         est dans un intervalle.
1170         Pour une liste on verifie que tous les elements sont
1171         dans l'intervalle
1172         Susceptible de remplacer les attributs "vale_min" "vale_max"
1173         dans les catalogues
1174     """
1175
1176     def __init__(self, low, high):
1177         self.low = low
1178         self.high = high
1179         self.cata_info = ufmt(_(u"%s doit être inférieur a %s"), low, high)
1180
1181     def info(self):
1182         return ufmt(_(u"valeur dans l'intervalle %s , %s"), self.low, self.high)
1183
1184     def convert_item(self, valeur):
1185         if valeur > self.low and valeur < self.high:
1186             return valeur
1187         raise ValError(ufmt(_(u"%s devrait être comprise entre %s et %s"),
1188                             valeur, self.low, self.high))
1189
1190     def verif_item(self, valeur):
1191         return valeur > self.low and valeur < self.high
1192
1193     def info_erreur_item(self):
1194         return ufmt(_(u"La valeur doit etre comprise entre %s et %s"), self.low, self.high)
1195
1196     def verif_cata(self):
1197         if self.low > self.high:
1198             return 0
1199         return 1
1200
1201
1202 class CardVal(Valid):
1203
1204     """
1205         Exemple de classe validateur : verification qu'une liste est
1206         d'une longueur superieur a un minimum (min) et inferieure
1207         a un maximum (max).
1208         Susceptible de remplacer les attributs "min" "max" dans les
1209         catalogues
1210     """
1211
1212     def __init__(self, min='**', max='**'):
1213         self.min = min
1214         self.max = max
1215         self.cata_info = ufmt(_(u"%s doit etre inferieur a %s"), min, max)
1216
1217     def info(self):
1218         return ufmt(_(u"longueur de liste comprise entre  %s et %s"), self.min, self.max)
1219
1220     def info_erreur_liste(self):
1221         return ufmt(
1222             _(u"Le cardinal de la liste doit etre compris entre %s et %s"),
1223             self.min, self.max)
1224
1225     def is_list(self):
1226         return self.max == '**' or self.max > 1
1227
1228     def get_into(self, liste_courante=None, into_courant=None):
1229         if into_courant is None:
1230             return None
1231         elif liste_courante is None:
1232             return into_courant
1233         elif self.max == '**':
1234             return into_courant
1235         elif len(liste_courante) < self.max:
1236             return into_courant
1237         else:
1238             return []
1239
1240     def convert(self, valeur):
1241         if is_sequence(valeur):
1242             l = len(valeur)
1243         elif valeur is None:
1244             l = 0
1245         else:
1246             l = 1
1247         if self.max != '**' and l > self.max:
1248             raise ValError(
1249                 ufmt(_(u"%s devrait etre de longueur inferieure a %s"), valeur, self.max))
1250         if self.min != '**' and l < self.min:
1251             raise ValError(
1252                 ufmt(_(u"%s devrait etre de longueur superieure a %s"), valeur, self.min))
1253         return valeur
1254
1255     def verif_item(self, valeur):
1256         return 1
1257
1258     def verif(self, valeur):
1259         if is_sequence(valeur):
1260             if self.max != '**' and len(valeur) > self.max:
1261                 return 0
1262             if self.min != '**' and len(valeur) < self.min:
1263                 return 0
1264             return 1
1265         else:
1266             if self.max != '**' and 1 > self.max:
1267                 return 0
1268             if self.min != '**' and 1 < self.min:
1269                 return 0
1270             return 1
1271
1272     def verif_cata(self):
1273         if self.min != '**' and self.max != '**' and self.min > self.max:
1274             return 0
1275         return 1
1276
1277     def valide_liste_partielle(self, liste_courante=None):
1278         validite = 1
1279         if liste_courante != None:
1280             if len(liste_courante) > self.max:
1281                 validite = 0
1282         return validite
1283
1284
1285 class PairVal(ListVal):
1286
1287     """
1288         Exemple de classe validateur : verification qu'une valeur
1289         est paire.
1290         Pour une liste on verifie que tous les elements sont
1291         pairs
1292     """
1293
1294     def __init__(self):
1295         ListVal.__init__(self)
1296         self.cata_info = ""
1297
1298     def info(self):
1299         return _(u"valeur paire")
1300
1301     def info_erreur_item(self):
1302         return _(u"La valeur saisie doit etre paire")
1303
1304     def convert(self, valeur):
1305         for val in valeur:
1306             v = self.adapt(val)
1307             if v % 2 != 0:
1308                 raise ValError(
1309                     ufmt(_(u"%s contient des valeurs non paires"), repr(valeur)))
1310         return valeur
1311
1312     def default(self, valeur):
1313         return valeur
1314
1315     def verif_item(self, valeur):
1316         if type(valeur) not in (int, long):
1317             return 0
1318         return valeur % 2 == 0
1319
1320     def verif(self, valeur):
1321         if is_sequence(valeur):
1322             for val in valeur:
1323                 if val % 2 != 0:
1324                     return 0
1325             return 1
1326         else:
1327             if valeur % 2 != 0:
1328                 return 0
1329             return 1
1330
1331
1332 class EnumVal(ListVal):
1333
1334     """
1335         Exemple de classe validateur : verification qu'une valeur
1336         est prise dans une liste de valeurs.
1337         Susceptible de remplacer l attribut "into" dans les catalogues
1338     """
1339
1340     def __init__(self, into=()):
1341         if not is_sequence(into):
1342             into = (into,)
1343         self.into = into
1344         self.cata_info = ""
1345
1346     def info(self):
1347         return "valeur dans %s" % `self.into`
1348
1349     def convert_item(self, valeur):
1350         if valeur in self.into:
1351             return valeur
1352         raise ValError(
1353             ufmt(_(u"%s contient des valeurs hors des choix possibles: %s "),
1354                  valeur, self.into))
1355
1356     def verif_item(self, valeur):
1357         if valeur not in self.into:
1358             return 0
1359         return 1
1360
1361     def has_into(self):
1362         return 1
1363
1364     def get_into(self, liste_courante=None, into_courant=None):
1365         if into_courant is None:
1366             liste_choix = list(self.into)
1367         else:
1368             liste_choix = []
1369             for e in into_courant:
1370                 if e in self.into:
1371                     liste_choix.append(e)
1372         return liste_choix
1373
1374     def info_erreur_item(self):
1375         return _(u"La valeur n'est pas dans la liste des choix possibles")
1376
1377
1378 def ImpairVal(valeur):
1379     """
1380           Exemple de validateur
1381         Cette fonction est un validateur. Elle verifie que la valeur passee
1382         est bien un nombre impair.
1383     """
1384     if is_sequence(valeur):
1385         for val in valeur:
1386             if val % 2 != 1:
1387                 return 0
1388         return 1
1389     else:
1390         if valeur % 2 != 1:
1391             return 0
1392         return 1
1393
1394 ImpairVal.info = "valeur impaire"
1395
1396
1397 class F1Val(Valid):
1398
1399     """
1400         Exemple de validateur
1401         Cette classe est un validateur de dictionnaire (mot cle facteur ?). Elle verifie
1402         que la somme des cles A et B vaut une valeur donnee
1403         en parametre du validateur
1404     """
1405
1406     def __init__(self, somme=10):
1407         self.somme = somme
1408         self.cata_info = ""
1409
1410     def info(self):
1411         return ufmt(_(u"valeur %s pour la somme des cles A et B "), self.somme)
1412
1413     def verif(self, valeur):
1414         if is_sequence(valeur):
1415             for val in valeur:
1416                 if not val.has_key("A"):
1417                     return 0
1418                 if not val.has_key("B"):
1419                     return 0
1420                 if val["A"] + val["B"] != self.somme:
1421                     return 0
1422             return 1
1423         else:
1424             if not valeur.has_key("A"):
1425                 return 0
1426             if not valeur.has_key("B"):
1427                 return 0
1428             if valeur["A"] + valeur["B"] != self.somme:
1429                 return 0
1430             return 1
1431
1432
1433 class FunctionVal(Valid):
1434
1435     """
1436         Exemple de validateur
1437         Cette classe est un validateur qui est initialise avec une fonction
1438     """
1439
1440     def __init__(self, function):
1441         self.function = function
1442
1443     def info(self):
1444         return self.function.info
1445
1446     def verif(self, valeur):
1447         return self.function(valeur)
1448
1449     def verif_item(self, valeur):
1450         return self.function(valeur)
1451
1452     def convert(self, valeur):
1453         return valeur
1454
1455 # MC ca ne devrait plus servir !
1456 CoercableFuncs = {types.IntType:     int,
1457                   types.LongType:    long,
1458                   types.FloatType:   float,
1459                   types.ComplexType: complex,
1460                   types.UnicodeType: unicode}
1461
1462
1463 class TypeVal(ListVal):
1464
1465     """
1466         Exemple de validateur
1467         Cette classe est un validateur qui controle qu'une valeur
1468         est bien du type Python attendu.
1469         Pour une liste on verifie que tous les elements sont du bon type.
1470         Semblable a InstanceVal mais ici on fait le test par tentative de conversion
1471         alors qu'avec InstanceVal on ne teste que si isinstance est vrai.
1472     """
1473
1474     def __init__(self, aType):
1475         # Si aType n'est pas un type, on le retrouve a l'aide de la fonction type
1476         # type(1) == int;type(0.2)==float;etc.
1477         if type(aType) != types.TypeType:
1478             aType = type(aType)
1479         self.aType = aType
1480         try:
1481             self.coerce = CoercableFuncs[aType]
1482         except:
1483             self.coerce = self.identity
1484
1485     def info(self):
1486         return ufmt(_(u"valeur de %s"), self.aType)
1487
1488     def identity(self, value):
1489         if type(value) == self.aType:
1490             return value
1491         raise ValError
1492
1493     def convert_item(self, valeur):
1494         return self.coerce(valeur)
1495
1496     def verif_item(self, valeur):
1497         try:
1498             self.coerce(valeur)
1499         except:
1500             return 0
1501         return 1
1502
1503
1504 class InstanceVal(ListVal):
1505
1506     """
1507         Exemple de validateur
1508         Cette classe est un validateur qui controle qu'une valeur est
1509         bien une instance (au sens Python) d'une classe
1510         Pour une liste on verifie chaque element de la liste
1511     """
1512
1513     def __init__(self, aClass):
1514         # Si aClass est une classe on la memorise dans self.aClass
1515         # sinon c'est une instance dont on memorise la classe
1516         if type(aClass) == types.InstanceType:
1517             # instance ancienne mode
1518             aClass = aClass.__class__
1519         elif type(aClass) == types.ClassType:
1520             # classe ancienne mode
1521             aClass = aClass
1522         elif type(aClass) == type:
1523             # classe nouvelle mode
1524             aClass = aClass
1525         elif isinstance(aClass, object):
1526             # instance nouvelle mode
1527             aClass = type(aClass)
1528         else:
1529             raise ValError(_(u"type non supporté"))
1530
1531         self.aClass = aClass
1532
1533     def info(self):
1534         return ufmt(_(u"valeur d'instance de %s"), self.aClass.__name__)
1535
1536     def verif_item(self, valeur):
1537         if not isinstance(valeur, self.aClass):
1538             return 0
1539         return 1
1540
1541
1542 class VerifTypeTuple(Valid, ListVal):
1543
1544     def __init__(self, typeDesTuples):
1545         self.typeDesTuples = typeDesTuples
1546         Valid.__init__(self)
1547         self.cata_info = ""
1548
1549     def info(self):
1550         return _(u": vérifie les types dans un tuple")
1551
1552     def info_erreur_liste(self):
1553         return _(u"Les types entrés ne sont pas permis")
1554
1555     def default(self, valeur):
1556         # if valeur in self.liste : raise ValError("%s est un doublon" %
1557         # valeur)
1558         return valeur
1559
1560     def is_list(self):
1561         return 1
1562
1563     def convert_item(self, valeur):
1564         if len(valeur) != len(self.typeDesTuples):
1565             raise ValError(
1566                 ufmt(_(u"%s devrait etre de type  %s "), valeur, self.typeDesTuples))
1567         for i in range(len(valeur)):
1568             ok = self.verifType(valeur[i], self.typeDesTuples[i])
1569             if ok != 1:
1570                 raise ValError(
1571                     ufmt(_(u"%s devrait etre de type  %s "), valeur, self.typeDesTuples))
1572         return valeur
1573
1574     def verif_item(self, valeur):
1575         try:
1576             if len(valeur) != len(self.typeDesTuples):
1577                 return 0
1578             for i in range(len(valeur)):
1579                 ok = self.verifType(valeur[i], self.typeDesTuples[i])
1580                 if ok != 1:
1581                     return 0
1582         except:
1583             return 0
1584         return 1
1585
1586     def verifType(self, valeur, type_permis):
1587         if type_permis == 'R':
1588             if type(valeur) in (types.IntType, types.FloatType, types.LongType):
1589                 return 1
1590         elif type_permis == 'I':
1591             if type(valeur) in (types.IntType, types.LongType):
1592                 return 1
1593         elif type_permis == 'C':
1594             if self.is_complexe(valeur):
1595                 return 1
1596         elif type_permis == 'TXM':
1597             if type(valeur) == types.StringType:
1598                 return 1
1599         return 0
1600
1601     def verif(self, valeur):
1602         if type(valeur) in (types.ListType, types.TupleType):
1603             liste = list(valeur)
1604             for val in liste:
1605                 if self.verif_item(val) != 1:
1606                     return 0
1607             return 1
1608
1609
1610 class VerifExiste(ListVal):
1611
1612     """
1613        fonctionne avec into
1614        Met une liste à jour selon les mot clefs existant
1615        exemple si into = ("A","B","C")
1616        si au niveau N du JDC les objets "A" et "C" existe
1617        alors la liste des into deviendra ( "A","C")
1618
1619        niveauVerif est le niveau du JDC dans lequel va s effectuer la verification
1620        niveauVerif est defini par rapport au Noeud :
1621        exemple niveauVerif = 1 : on verifie les freres
1622                niveauVerif = 2 : on verifie les oncles..
1623     """
1624
1625     def __init__(self, niveauVerif):
1626         ListVal.__init__(self)
1627         self.niveauVerif = niveauVerif
1628         self.MCSimp = None
1629         self.listeDesFreres = ()
1630         self.fonctions = ('verifie_liste', 'set_MCSimp')
1631
1632     def is_list(self):
1633         return 1
1634
1635     def verifie_liste(self, liste):
1636         self.set_MCSimp(self.MCSimp)
1637         for item in liste:
1638             if not(item in self.listeDesFreres):
1639                 return 0
1640         return 1
1641
1642     def verif_item(self, valeur):
1643         self.set_MCSimp(self.MCSimp)
1644         if valeur in self.listeDesFreres:
1645             return 1
1646         return 0
1647
1648     def set_MCSimp(self, MCSimp):
1649         self.MCSimp = MCSimp
1650         k = self.niveauVerif
1651         mc = MCSimp
1652         while (k != 0):
1653             parent = mc.parent
1654             mc = parent
1655             k = k - 1
1656         # on met la liste à jour
1657         parent.forceRecalcul = self.niveauVerif
1658         self.listeDesFreres = parent.liste_mc_presents()
1659
1660     def convert_item(self, valeur):
1661         if valeur in self.listeDesFreres:
1662             return valeur
1663         raise ValError(
1664             ufmt(_(u"%s n'est pas dans %s"), valeur, self.listeDesFreres))
1665
1666
1667 class RegExpVal(ListVal):
1668
1669     """
1670     Vérifie qu'une chaîne de caractère corresponde à l'expression régulière 'pattern'
1671     """
1672
1673     errormsg = u'La chaîne "%(value)s" ne correspond pas au motif "%(pattern)s"'
1674
1675     def __init__(self, pattern):
1676         self.pattern = pattern
1677         self.compiled_regexp = re.compile(pattern)
1678
1679     def info(self):
1680         return u'Une chaîne correspondant au motif "%s" est attendue.' % self.pattern
1681
1682     def verif_item(self, valeur):
1683         if self.compiled_regexp.match(valeur):
1684             return 1
1685         else:
1686             return (0, self.errormsg % {"value": valeur, "pattern": self.pattern})
1687
1688     def convert_item(self, valeur):
1689         if self.compiled_regexp.match(valeur):
1690             return valeur
1691         else:
1692             raise ValError(self.errormsg %
1693                            {"value": valeur, "pattern": self.pattern})
1694
1695
1696 class FileExtVal(RegExpVal):
1697
1698     """
1699     Vérifie qu'une chaîne de caractère soit un nom de fichier valide avec l'extension 'ext'
1700     """
1701
1702     def __init__(self, ext):
1703         self.ext = ext
1704         self.errormsg = u'"%%(value)s" n\'est pas un nom de fichier %(ext)s valide' % {
1705             "ext": ext}
1706         #RegExpVal.__init__(self, "^[\w\-]+\.%s$" % self.ext)
1707         #PNPN Modif pour Adao
1708         #RegExpVal.__init__(self, "^[\S]+\.%s$" % self.ext
1709         RegExpVal.__init__(self, "^\S+\.%s$" % self.ext)
1710
1711
1712     def info(self):
1713         return u'Un nom de fichier se terminant par ".%s" est attendu.' % self.ext