Salome HOME
chgt noyau pour aster
[tools/eficas.git] / Noyau / N_VALIDATOR.py
1 # coding=utf-8
2 # Copyright (C) 2007-2013   EDF R&D
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 #
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
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     """
513         Validateur operationnel
514         Verification de la présence obligatoire d'un élément dans une liste
515     """
516     registry = {}
517
518     def __init__(self, elem=()):
519         if not is_sequence(elem):
520             elem = (elem,)
521         Valid.__init__(self, elem=elem)
522         self.elem = elem
523         self.cata_info = ""
524
525     def info(self):
526         return ufmt(_(u"valeur %s obligatoire"), `self.elem`)
527
528     def default(self, valeur, elem):
529         return valeur
530
531     def verif_item(self, valeur):
532         return 1
533
534     def convert(self, valeur):
535         elem = list(self.elem)
536         for val in valeur:
537             v = self.adapt(val)
538             if v in elem:
539                 elem.remove(v)
540         if elem:
541             raise ValError(
542                 ufmt(_(u"%s ne contient pas les elements obligatoires : %s "),
543                      valeur, elem))
544         return valeur
545
546     def has_into(self):
547         return 1
548
549     def verif(self, valeur):
550         if not is_sequence(valeur):
551             liste = list(valeur)
552         else:
553             liste = valeur
554         for val in self.elem:
555             if val not in liste:
556                 return 0
557         return 1
558
559     def info_erreur_item(self):
560         return _(u"La valeur n'est pas dans la liste des choix possibles")
561
562
563 class NoRepeat(ListVal):
564
565     """
566         Validateur operationnel
567         Verification d'absence de doublons dans la liste.
568     """
569
570     def __init__(self):
571         Valid.__init__(self)
572         self.cata_info = ""
573
574     def info(self):
575         return _(u": pas de présence de doublon dans la liste")
576
577     def info_erreur_liste(self):
578         return _(u"Les doublons ne sont pas permis")
579
580     def default(self, valeur):
581         if valeur in self.liste:
582             raise ValError(ufmt(_(u"%s est un doublon"), valeur))
583         return valeur
584
585     def convert(self, valeur):
586         self.liste = []
587         for val in valeur:
588             v = self.adapt(val)
589             self.liste.append(v)
590         return valeur
591
592     def verif_item(self, valeur):
593         return 1
594
595     def verif(self, valeur):
596         if is_sequence(valeur):
597             liste = list(valeur)
598             for val in liste:
599                 if liste.count(val) != 1:
600                     return 0
601             return 1
602         else:
603             return 1
604
605     def get_into(self, liste_courante=None, into_courant=None):
606         """
607         Methode get_into spécifique pour validateur NoRepeat, on retourne
608         une liste de choix qui ne contient aucune valeur de into_courant
609         déjà contenue dans liste_courante
610         """
611         if into_courant is None:
612             liste_choix = None
613         else:
614             liste_choix = []
615             for e in into_courant:
616                 if e in liste_choix:
617                     continue
618                 if liste_courante is not None and e in liste_courante:
619                     continue
620                 liste_choix.append(e)
621         return liste_choix
622
623
624 class LongStr(ListVal):
625
626     """
627         Validateur operationnel
628         Verification de la longueur d une chaine
629     """
630
631     def __init__(self, low, high):
632         ListVal.__init__(self, low=low, high=high)
633         self.low = low
634         self.high = high
635         self.cata_info = ""
636
637     def info(self):
638         return ufmt(_(u"longueur de la chaine entre %s et %s"), self.low, self.high)
639
640     def info_erreur_item(self):
641         return _(u"Longueur de la chaine incorrecte")
642
643     def convert(self, valeur):
644         for val in valeur:
645             v = self.adapt(val)
646         return valeur
647
648     def verif_item(self, valeur):
649         try:
650             self.adapt(valeur)
651             return 1
652         except:
653             return 0
654
655     def default(self, valeur, low, high):
656         if not is_str(valeur):
657             raise ValError(ufmt(_(u"%s n'est pas une chaine"), repr(valeur)))
658         if valeur[0] == "'" and valeur[-1] == "'":
659             low = low + 2
660             high = high + 2
661         if len(valeur) < low or len(valeur) > high:
662             raise ValError(
663                 ufmt(_(u"%s n'est pas de la bonne longueur"), repr(valeur)))
664         return valeur
665
666
667 class OnlyStr(ListVal):
668
669     """
670         Validateur operationnel
671         Valide que c'est une chaine
672     """
673
674     def __init__(self):
675         ListVal.__init__(self)
676         self.cata_info = ""
677
678     def info(self):
679         return _(u"regarde si c'est une chaine")
680
681     def info_erreur_item(self):
682         return _(u"Ce n'est pas une chaine")
683
684     def convert(self, valeur):
685         for val in valeur:
686             v = self.adapt(val)
687         return valeur
688
689     def verif_item(self, valeur):
690         try:
691             self.adapt(valeur)
692             return 1
693         except:
694             return 0
695
696     def default(self, valeur):
697         if not is_str(valeur):
698             raise ValError(ufmt(_(u"%s n'est pas une chaine"), repr(valeur)))
699         return valeur
700
701
702 class OrdList(ListVal):
703
704     """
705         Validateur operationnel
706         Verification qu'une liste est croissante ou decroissante
707     """
708
709     def __init__(self, ord):
710         ListVal.__init__(self, ord=ord)
711         self.ord = ord
712         self.cata_info = ""
713
714     def info(self):
715         return ufmt(_(u"liste %s"), self.ord)
716
717     def info_erreur_liste(self):
718         return ufmt(_(u"La liste doit etre en ordre %s"), self.ord)
719
720     def convert(self, valeur):
721         self.val = None
722         self.liste = valeur
723         for v in valeur:
724             self.adapt(v)
725         return valeur
726
727     def default(self, valeur, ord):
728         if self.ord == 'croissant':
729             if self.val is not None and valeur < self.val:
730                 raise ValError(
731                     ufmt(_(u"%s n'est pas par valeurs croissantes"), repr(self.liste)))
732         elif self.ord == 'decroissant':
733             if self.val is not None and valeur > self.val:
734                 raise ValError(
735                     ufmt(_(u"%s n'est pas par valeurs decroissantes"), repr(self.liste)))
736         self.val = valeur
737         return valeur
738
739     def verif_item(self, valeur):
740         return 1
741
742     def get_into(self, liste_courante=None, into_courant=None):
743         """
744         Methode get_into spécifique pour validateur OrdList, on retourne
745         une liste de choix qui ne contient aucune valeur de into_courant
746         dont la valeur est inférieure à la dernière valeur de
747         liste_courante, si elle est différente de None.
748         """
749         if into_courant is None:
750             return None
751         elif not liste_courante:
752             return into_courant
753         else:
754             liste_choix = []
755             last_val = liste_choix[-1]
756             for e in into_courant:
757                 if self.ord == 'croissant' and e <= last_val:
758                     continue
759                 if self.ord == 'decroissant' and e >= last_val:
760                     continue
761                 liste_choix.append(e)
762             return liste_choix
763
764
765 class OrVal(Valid):
766
767     """
768         Validateur operationnel
769         Cette classe est un validateur qui controle une liste de validateurs
770         Elle verifie qu'au moins un des validateurs de la liste valide la valeur
771     """
772
773     def __init__(self, validators=()):
774         if not is_sequence(validators):
775             validators = (validators,)
776         self.validators = []
777         for validator in validators:
778             if type(validator) == types.FunctionType:
779                 self.validators.append(FunctionVal(validator))
780             else:
781                 self.validators.append(validator)
782         self.cata_info = ""
783
784     def info(self):
785         return "\n ou ".join([v.info() for v in self.validators])
786
787     def convert(self, valeur):
788         for validator in self.validators:
789             try:
790                 return validator.convert(valeur)
791             except:
792                 pass
793         raise ValError(ufmt(_(u"%s n'est pas du bon type"), repr(valeur)))
794
795     def info_erreur_item(self):
796         l = []
797         for v in self.validators:
798             err = v.info_erreur_item()
799             if err != " ":
800                 l.append(err)
801         chaine = " \n ou ".join(l)
802         return chaine
803
804     def info_erreur_liste(self):
805         l = []
806         for v in self.validators:
807             err = v.info_erreur_liste()
808             if err != " ":
809                 l.append(err)
810         chaine = " \n ou ".join(l)
811         return chaine
812
813     def is_list(self):
814         """
815            Si plusieurs validateurs sont reliés par un OU
816            il suffit qu'un seul des validateurs attende une liste
817            pour qu'on considère que leur union attend une liste.
818         """
819         for validator in self.validators:
820             v = validator.is_list()
821             if v:
822                 return 1
823         return 0
824
825     def verif(self, valeur):
826         for validator in self.validators:
827             v = validator.verif(valeur)
828             if v:
829                 return 1
830         return 0
831
832     def verif_item(self, valeur):
833         for validator in self.validators:
834             v = validator.verif_item(valeur)
835             if v:
836                 return 1
837         return 0
838
839     def verif_cata(self):
840         infos = []
841         for validator in self.validators:
842             v = validator.verif_cata()
843             if not v:
844                 infos.append(validator.cata_info)
845         if infos:
846             self.cata_info = "\n".join(infos)
847             return 0
848         self.cata_info = ""
849         return 1
850
851     def has_into(self):
852         """
853         Dans le cas ou plusieurs validateurs sont reliés par un OU
854         il faut que tous les validateurs proposent un choix pour
855         qu'on considère que leur union propose un choix.
856         Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix
857         En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un choix (1,2,3,4,5,6)
858         """
859         for validator in self.validators:
860             v = validator.has_into()
861             if not v:
862                 return 0
863         return 1
864
865     def get_into(self, liste_courante=None, into_courant=None):
866         """
867         Dans le cas ou plusieurs validateurs sont reliés par un OU
868         tous les validateurs doivent proposer un choix pour
869         qu'on considère que leur union propose un choix. Tous les choix
870         proposés par les validateurs sont réunis (opérateur d'union).
871         Exemple : Enum(1,2,3) OU entier pair, ne propose pas de choix
872         En revanche, Enum(1,2,3) OU Enum(4,5,6) propose un
873         choix (1,2,3,4,5,6)
874         """
875         validator_into = []
876         for validator in self.validators:
877             v_into = validator.get_into(liste_courante, into_courant)
878             if v_into is None:
879                 return v_into
880             validator_into.extend(v_into)
881         return validator_into
882
883     def valide_liste_partielle(self, liste_courante=None):
884         """
885          Méthode de validation de liste partielle pour le validateur Or.
886          Si un des validateurs gérés par le validateur Or considère la
887          liste comme valide, le validateur Or la considère comme valide.
888         """
889         for validator in self.validators:
890             v = validator.valide_liste_partielle(liste_courante)
891             if v:
892                 return 1
893         return 0
894
895
896 class AndVal(Valid):
897
898     """
899         Validateur operationnel
900         Cette classe est un validateur qui controle une liste de validateurs
901         Elle verifie que tous les validateurs de la liste valident la valeur
902     """
903
904     def __init__(self, validators=()):
905         if not is_sequence(validators):
906             validators = (validators,)
907         self.validators = []
908         for validator in validators:
909             if type(validator) == types.FunctionType:
910                 self.validators.append(FunctionVal(validator))
911             else:
912                 self.validators.append(validator)
913             if hasattr(validator, 'fonctions'):
914                 for fonction in validator.fonctions:
915                     f = getattr(validator, fonction)
916                     setattr(self, fonction, f)
917         self.cata_info = ""
918
919     def info(self):
920         return "\n et ".join([v.info() for v in self.validators])
921
922     def convert(self, valeur):
923         for validator in self.validators:
924             valeur = validator.convert(valeur)
925         return valeur
926
927     def info_erreur_item(self):
928         chaine = ""
929         a = 1
930         for v in self.validators:
931             if v.info_erreur_item() != " ":
932                 if a == 1:
933                     chaine = v.info_erreur_item()
934                     a = 0
935                 else:
936                     chaine = chaine + " \n et " + v.info_erreur_item()
937         return chaine
938
939     def info_erreur_liste(self):
940         a = 1
941         for v in self.validators:
942             if v.info_erreur_liste() != " ":
943                 if a == 1:
944                     chaine = v.info_erreur_liste()
945                     a = 0
946                 else:
947                     chaine = chaine + " \n et " + v.info_erreur_liste()
948         return chaine
949
950     def verif(self, valeur):
951         for validator in self.validators:
952             v = validator.verif(valeur)
953             if not v:
954                 self.local_info = validator.info()
955                 return 0
956         return 1
957
958     def verif_item(self, valeur):
959         for validator in self.validators:
960             v = validator.verif_item(valeur)
961             if not v:
962                 # L'info n'est probablement pas la meme que pour verif ???
963                 self.local_info = validator.info()
964                 return 0
965         return 1
966
967     def verif_cata(self):
968         infos = []
969         for validator in self.validators:
970             v = validator.verif_cata()
971             if not v:
972                 infos.append(validator.cata_info)
973         if infos:
974             self.cata_info = "\n".join(infos)
975             return 0
976         self.cata_info = ""
977         return 1
978
979     def valide_liste_partielle(self, liste_courante=None):
980         """
981          Méthode de validation de liste partielle pour le validateur And.
982          Tous les validateurs gérés par le validateur And doivent considérer
983          la liste comme valide, pour que le validateur And la considère
984          comme valide.
985         """
986         for validator in self.validators:
987             v = validator.valide_liste_partielle(liste_courante)
988             if not v:
989                 return 0
990         return 1
991
992     def is_list(self):
993         """
994         Si plusieurs validateurs sont reliés par un ET
995         il faut que tous les validateurs attendent une liste
996         pour qu'on considère que leur intersection attende une liste.
997         Exemple Range(2,5) ET Card(1) n'attend pas une liste
998         Range(2,5) ET Pair attend une liste
999         """
1000         for validator in self.validators:
1001             v = validator.is_list()
1002             if v == 0:
1003                 return 0
1004         return 1
1005
1006     def has_into(self):
1007         """
1008         Dans le cas ou plusieurs validateurs sont reliés par un ET
1009         il suffit qu'un seul validateur propose un choix pour
1010         qu'on considère que leur intersection propose un choix.
1011         Exemple : Enum(1,2,3) ET entier pair, propose un choix
1012         En revanche, entier pair ET superieur à 10 ne propose pas de choix
1013         """
1014         for validator in self.validators:
1015             v = validator.has_into()
1016             if v:
1017                 return 1
1018         return 0
1019
1020     def get_into(self, liste_courante=None, into_courant=None):
1021         """
1022         Dans le cas ou plusieurs validateurs sont reliés par un ET
1023         il suffit qu'un seul validateur propose un choix pour
1024         qu'on considère que leur intersection propose un choix. Tous les
1025         choix proposés par les validateurs sont croisés (opérateur
1026         d'intersection)
1027         Exemple : Enum(1,2,3) ET entier pair, propose un choix (2,)
1028         En revanche, Enum(1,2,3) ET Enum(4,5,6) ne propose pas de choix.
1029         """
1030         for validator in self.validators:
1031             into_courant = validator.get_into(liste_courante, into_courant)
1032             if into_courant in ([], None):
1033                 break
1034         return into_courant
1035
1036
1037 def do_liste(validators):
1038     """
1039        Convertit une arborescence de validateurs en OrVal ou AndVal
1040        validators est une liste de validateurs ou de listes ou de tuples
1041     """
1042     valids = []
1043     for validator in validators:
1044         if type(validator) == types.FunctionType:
1045             valids.append(FunctionVal(validator))
1046         elif type(validator) is tuple:
1047             valids.append(OrVal(do_liste(validator)))
1048         elif type(validator) is list:
1049             valids.append(AndVal(do_liste(validator)))
1050         else:
1051             valids.append(validator)
1052     return valids
1053
1054
1055 def validatorFactory(validator):
1056     if type(validator) == types.FunctionType:
1057         return FunctionVal(validator)
1058     elif type(validator) is tuple:
1059         return OrVal(do_liste(validator))
1060     elif type(validator) is list:
1061         return AndVal(do_liste(validator))
1062     else:
1063         return validator
1064
1065 # Ci-dessous : exemples de validateur (peu testés)
1066
1067
1068 class RangeVal(ListVal):
1069
1070     """
1071         Exemple de classe validateur : verification qu'une valeur
1072         est dans un intervalle.
1073         Pour une liste on verifie que tous les elements sont
1074         dans l'intervalle
1075         Susceptible de remplacer les attributs "vale_min" "vale_max"
1076         dans les catalogues
1077     """
1078
1079     def __init__(self, low, high):
1080         self.low = low
1081         self.high = high
1082         self.cata_info = ufmt(_(u"%s doit être inférieur a %s"), low, high)
1083
1084     def info(self):
1085         return ufmt(_(u"valeur dans l'intervalle %s , %s"), self.low, self.high)
1086
1087     def convert_item(self, valeur):
1088         if valeur > self.low and valeur < self.high:
1089             return valeur
1090         raise ValError(ufmt(_(u"%s devrait être comprise entre %s et %s"),
1091                             valeur, self.low, self.high))
1092
1093     def verif_item(self, valeur):
1094         return valeur > self.low and valeur < self.high
1095
1096     def info_erreur_item(self):
1097         return ufmt(_(u"La valeur doit etre comprise entre %s et %s"), self.low, self.high)
1098
1099     def verif_cata(self):
1100         if self.low > self.high:
1101             return 0
1102         return 1
1103
1104
1105 class CardVal(Valid):
1106
1107     """
1108         Exemple de classe validateur : verification qu'une liste est
1109         d'une longueur superieur a un minimum (min) et inferieure
1110         a un maximum (max).
1111         Susceptible de remplacer les attributs "min" "max" dans les
1112         catalogues
1113     """
1114
1115     def __init__(self, min='**', max='**'):
1116         self.min = min
1117         self.max = max
1118         self.cata_info = ufmt(_(u"%s doit etre inferieur a %s"), min, max)
1119
1120     def info(self):
1121         return ufmt(_(u"longueur de liste comprise entre  %s et %s"), self.min, self.max)
1122
1123     def info_erreur_liste(self):
1124         return ufmt(
1125             _(u"Le cardinal de la liste doit etre compris entre %s et %s"),
1126             self.min, self.max)
1127
1128     def is_list(self):
1129         return self.max == '**' or self.max > 1
1130
1131     def get_into(self, liste_courante=None, into_courant=None):
1132         if into_courant is None:
1133             return None
1134         elif liste_courante is None:
1135             return into_courant
1136         elif self.max == '**':
1137             return into_courant
1138         elif len(liste_courante) < self.max:
1139             return into_courant
1140         else:
1141             return []
1142
1143     def convert(self, valeur):
1144         if is_sequence(valeur):
1145             l = len(valeur)
1146         elif valeur is None:
1147             l = 0
1148         else:
1149             l = 1
1150         if self.max != '**' and l > self.max:
1151             raise ValError(
1152                 ufmt(_(u"%s devrait etre de longueur inferieure a %s"), valeur, self.max))
1153         if self.min != '**' and l < self.min:
1154             raise ValError(
1155                 ufmt(_(u"%s devrait etre de longueur superieure a %s"), valeur, self.min))
1156         return valeur
1157
1158     def verif_item(self, valeur):
1159         return 1
1160
1161     def verif(self, valeur):
1162         if is_sequence(valeur):
1163             if self.max != '**' and len(valeur) > self.max:
1164                 return 0
1165             if self.min != '**' and len(valeur) < self.min:
1166                 return 0
1167             return 1
1168         else:
1169             if self.max != '**' and 1 > self.max:
1170                 return 0
1171             if self.min != '**' and 1 < self.min:
1172                 return 0
1173             return 1
1174
1175     def verif_cata(self):
1176         if self.min != '**' and self.max != '**' and self.min > self.max:
1177             return 0
1178         return 1
1179
1180     def valide_liste_partielle(self, liste_courante=None):
1181         validite = 1
1182         if liste_courante != None:
1183             if len(liste_courante) > self.max:
1184                 validite = 0
1185         return validite
1186
1187
1188 class PairVal(ListVal):
1189
1190     """
1191         Exemple de classe validateur : verification qu'une valeur
1192         est paire.
1193         Pour une liste on verifie que tous les elements sont
1194         pairs
1195     """
1196
1197     def __init__(self):
1198         ListVal.__init__(self)
1199         self.cata_info = ""
1200
1201     def info(self):
1202         return _(u"valeur paire")
1203
1204     def info_erreur_item(self):
1205         return _(u"La valeur saisie doit etre paire")
1206
1207     def convert(self, valeur):
1208         for val in valeur:
1209             v = self.adapt(val)
1210             if v % 2 != 0:
1211                 raise ValError(
1212                     ufmt(_(u"%s contient des valeurs non paires"), repr(valeur)))
1213         return valeur
1214
1215     def default(self, valeur):
1216         return valeur
1217
1218     def verif_item(self, valeur):
1219         if type(valeur) not in (int, long):
1220             return 0
1221         return valeur % 2 == 0
1222
1223     def verif(self, valeur):
1224         if is_sequence(valeur):
1225             for val in valeur:
1226                 if val % 2 != 0:
1227                     return 0
1228             return 1
1229         else:
1230             if valeur % 2 != 0:
1231                 return 0
1232             return 1
1233
1234
1235 class EnumVal(ListVal):
1236
1237     """
1238         Exemple de classe validateur : verification qu'une valeur
1239         est prise dans une liste de valeurs.
1240         Susceptible de remplacer l attribut "into" dans les catalogues
1241     """
1242
1243     def __init__(self, into=()):
1244         if not is_sequence(into):
1245             into = (into,)
1246         self.into = into
1247         self.cata_info = ""
1248
1249     def info(self):
1250         return "valeur dans %s" % `self.into`
1251
1252     def convert_item(self, valeur):
1253         if valeur in self.into:
1254             return valeur
1255         raise ValError(
1256             ufmt(_(u"%s contient des valeurs hors des choix possibles: %s "),
1257                  valeur, self.into))
1258
1259     def verif_item(self, valeur):
1260         if valeur not in self.into:
1261             return 0
1262         return 1
1263
1264     def has_into(self):
1265         return 1
1266
1267     def get_into(self, liste_courante=None, into_courant=None):
1268         if into_courant is None:
1269             liste_choix = list(self.into)
1270         else:
1271             liste_choix = []
1272             for e in into_courant:
1273                 if e in self.into:
1274                     liste_choix.append(e)
1275         return liste_choix
1276
1277     def info_erreur_item(self):
1278         return _(u"La valeur n'est pas dans la liste des choix possibles")
1279
1280
1281 def ImpairVal(valeur):
1282     """
1283           Exemple de validateur
1284         Cette fonction est un validateur. Elle verifie que la valeur passee
1285         est bien un nombre impair.
1286     """
1287     if is_sequence(valeur):
1288         for val in valeur:
1289             if val % 2 != 1:
1290                 return 0
1291         return 1
1292     else:
1293         if valeur % 2 != 1:
1294             return 0
1295         return 1
1296
1297 ImpairVal.info = "valeur impaire"
1298
1299
1300 class F1Val(Valid):
1301
1302     """
1303         Exemple de validateur
1304         Cette classe est un validateur de dictionnaire (mot cle facteur ?). Elle verifie
1305         que la somme des cles A et B vaut une valeur donnee
1306         en parametre du validateur
1307     """
1308
1309     def __init__(self, somme=10):
1310         self.somme = somme
1311         self.cata_info = ""
1312
1313     def info(self):
1314         return ufmt(_(u"valeur %s pour la somme des cles A et B "), self.somme)
1315
1316     def verif(self, valeur):
1317         if is_sequence(valeur):
1318             for val in valeur:
1319                 if not val.has_key("A"):
1320                     return 0
1321                 if not val.has_key("B"):
1322                     return 0
1323                 if val["A"] + val["B"] != self.somme:
1324                     return 0
1325             return 1
1326         else:
1327             if not valeur.has_key("A"):
1328                 return 0
1329             if not valeur.has_key("B"):
1330                 return 0
1331             if valeur["A"] + valeur["B"] != self.somme:
1332                 return 0
1333             return 1
1334
1335
1336 class FunctionVal(Valid):
1337
1338     """
1339         Exemple de validateur
1340         Cette classe est un validateur qui est initialise avec une fonction
1341     """
1342
1343     def __init__(self, function):
1344         self.function = function
1345
1346     def info(self):
1347         return self.function.info
1348
1349     def verif(self, valeur):
1350         return self.function(valeur)
1351
1352 # MC ca ne devrait plus servir !
1353 CoercableFuncs = {types.IntType:     int,
1354                   types.LongType:    long,
1355                   types.FloatType:   float,
1356                   types.ComplexType: complex,
1357                   types.UnicodeType: unicode}
1358
1359
1360 class TypeVal(ListVal):
1361
1362     """
1363         Exemple de validateur
1364         Cette classe est un validateur qui controle qu'une valeur
1365         est bien du type Python attendu.
1366         Pour une liste on verifie que tous les elements sont du bon type.
1367         Semblable a InstanceVal mais ici on fait le test par tentative de conversion
1368         alors qu'avec InstanceVal on ne teste que si isinstance est vrai.
1369     """
1370
1371     def __init__(self, aType):
1372         # Si aType n'est pas un type, on le retrouve a l'aide de la fonction type
1373         # type(1) == int;type(0.2)==float;etc.
1374         if type(aType) != types.TypeType:
1375             aType = type(aType)
1376         self.aType = aType
1377         try:
1378             self.coerce = CoercableFuncs[aType]
1379         except:
1380             self.coerce = self.identity
1381
1382     def info(self):
1383         return ufmt(_(u"valeur de %s"), self.aType)
1384
1385     def identity(self, value):
1386         if type(value) == self.aType:
1387             return value
1388         raise ValError
1389
1390     def convert_item(self, valeur):
1391         return self.coerce(valeur)
1392
1393     def verif_item(self, valeur):
1394         try:
1395             self.coerce(valeur)
1396         except:
1397             return 0
1398         return 1
1399
1400
1401 class InstanceVal(ListVal):
1402
1403     """
1404         Exemple de validateur
1405         Cette classe est un validateur qui controle qu'une valeur est
1406         bien une instance (au sens Python) d'une classe
1407         Pour une liste on verifie chaque element de la liste
1408     """
1409
1410     def __init__(self, aClass):
1411         # Si aClass est une classe on la memorise dans self.aClass
1412         # sinon c'est une instance dont on memorise la classe
1413         if type(aClass) == types.InstanceType:
1414             # instance ancienne mode
1415             aClass = aClass.__class__
1416         elif type(aClass) == types.ClassType:
1417             # classe ancienne mode
1418             aClass = aClass
1419         elif type(aClass) == type:
1420             # classe nouvelle mode
1421             aClass = aClass
1422         elif isinstance(aClass, object):
1423             # instance nouvelle mode
1424             aClass = type(aClass)
1425         else:
1426             raise ValError(_(u"type non supporté"))
1427
1428         self.aClass = aClass
1429
1430     def info(self):
1431         return ufmt(_(u"valeur d'instance de %s"), self.aClass.__name__)
1432
1433     def verif_item(self, valeur):
1434         if not isinstance(valeur, self.aClass):
1435             return 0
1436         return 1
1437
1438
1439 class VerifTypeTuple(Valid, ListVal):
1440
1441     def __init__(self, typeDesTuples):
1442         self.typeDesTuples = typeDesTuples
1443         Valid.__init__(self)
1444         self.cata_info = ""
1445
1446     def info(self):
1447         return _(u": vérifie les types dans un tuple")
1448
1449     def info_erreur_liste(self):
1450         return _(u"Les types entrés ne sont pas permis")
1451
1452     def default(self, valeur):
1453         # if valeur in self.liste : raise ValError("%s est un doublon" %
1454         # valeur)
1455         return valeur
1456
1457     def is_list(self):
1458         return 1
1459
1460     def convert_item(self, valeur):
1461         if len(valeur) != len(self.typeDesTuples):
1462             raise ValError(
1463                 ufmt(_(u"%s devrait etre de type  %s "), valeur, self.typeDesTuples))
1464         for i in range(len(valeur)):
1465             ok = self.verifType(valeur[i], self.typeDesTuples[i])
1466             if ok != 1:
1467                 raise ValError(
1468                     ufmt(_(u"%s devrait etre de type  %s "), valeur, self.typeDesTuples))
1469         return valeur
1470
1471     def verif_item(self, valeur):
1472         try:
1473             if len(valeur) != len(self.typeDesTuples):
1474                 return 0
1475             for i in range(len(valeur)):
1476                 ok = self.verifType(valeur[i], self.typeDesTuples[i])
1477                 if ok != 1:
1478                     return 0
1479         except:
1480             return 0
1481         return 1
1482
1483     def verifType(self, valeur, type_permis):
1484         if type_permis == 'R':
1485             if type(valeur) in (types.IntType, types.FloatType, types.LongType):
1486                 return 1
1487         elif type_permis == 'I':
1488             if type(valeur) in (types.IntType, types.LongType):
1489                 return 1
1490         elif type_permis == 'C':
1491             if self.is_complexe(valeur):
1492                 return 1
1493         elif type_permis == 'TXM':
1494             if type(valeur) == types.StringType:
1495                 return 1
1496         return 0
1497
1498     def verif(self, valeur):
1499         if type(valeur) in (types.ListType, types.TupleType):
1500             liste = list(valeur)
1501             for val in liste:
1502                 if self.verif_item(val) != 1:
1503                     return 0
1504             return 1
1505
1506
1507 class VerifExiste(ListVal):
1508
1509     """
1510        fonctionne avec into
1511        Met une liste à jour selon les mot clefs existant
1512        exemple si into = ("A","B","C")
1513        si au niveau N du JDC les objets "A" et "C" existe
1514        alors la liste des into deviendra ( "A","C")
1515
1516        niveauVerif est le niveau du JDC dans lequel va s effectuer la verification
1517        niveauVerif est defini par rapport au Noeud :
1518        exemple niveauVerif = 1 : on verifie les freres
1519                niveauVerif = 2 : on verifie les oncles..
1520     """
1521
1522     def __init__(self, niveauVerif):
1523         ListVal.__init__(self)
1524         self.niveauVerif = niveauVerif
1525         self.MCSimp = None
1526         self.listeDesFreres = ()
1527         self.fonctions = ('verifie_liste', 'set_MCSimp')
1528
1529     def is_list(self):
1530         return 1
1531
1532     def verifie_liste(self, liste):
1533         self.set_MCSimp(self.MCSimp)
1534         for item in liste:
1535             if not(item in self.listeDesFreres):
1536                 return 0
1537         return 1
1538
1539     def verif_item(self, valeur):
1540         self.set_MCSimp(self.MCSimp)
1541         if valeur in self.listeDesFreres:
1542             return 1
1543         return 0
1544
1545     def set_MCSimp(self, MCSimp):
1546         self.MCSimp = MCSimp
1547         k = self.niveauVerif
1548         mc = MCSimp
1549         while (k != 0):
1550             parent = mc.parent
1551             mc = parent
1552             k = k - 1
1553         # on met la liste à jour
1554         parent.forceRecalcul = self.niveauVerif
1555         self.listeDesFreres = parent.liste_mc_presents()
1556
1557     def convert_item(self, valeur):
1558         if valeur in self.listeDesFreres:
1559             return valeur
1560         raise ValError(
1561             ufmt(_(u"%s n'est pas dans %s"), valeur, self.listeDesFreres))
1562
1563
1564 class RegExpVal(ListVal):
1565
1566     """
1567     Vérifie qu'une chaîne de caractère corresponde à l'expression régulière 'pattern'
1568     """
1569
1570     errormsg = u'La chaîne "%(value)s" ne correspond pas au motif "%(pattern)s"'
1571
1572     def __init__(self, pattern):
1573         self.pattern = pattern
1574         self.compiled_regexp = re.compile(pattern)
1575
1576     def info(self):
1577         return u'Une chaîne correspondant au motif "%s" est attendue.' % self.pattern
1578
1579     def verif_item(self, valeur):
1580         if self.compiled_regexp.match(valeur):
1581             return 1
1582         else:
1583             return (0, self.errormsg % {"value": valeur, "pattern": self.pattern})
1584
1585     def convert_item(self, valeur):
1586         if self.compiled_regexp.match(valeur):
1587             return valeur
1588         else:
1589             raise ValError(self.errormsg %
1590                            {"value": valeur, "pattern": self.pattern})
1591
1592
1593 class FileExtVal(RegExpVal):
1594
1595     """
1596     Vérifie qu'une chaîne de caractère soit un nom de fichier valide avec l'extension 'ext'
1597     """
1598
1599     def __init__(self, ext):
1600         self.ext = ext
1601         self.errormsg = u'"%%(value)s" n\'est pas un nom de fichier %(ext)s valide' % {
1602             "ext": ext}
1603         RegExpVal.__init__(self, "^[\w\-]+\.%s$" % self.ext)
1604
1605     def info(self):
1606         return u'Un nom de fichier se terminant par ".%s" est attendu.' % self.ext