bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
| 
1185.12.49
by Aaron Bentley
 Switched to ConfigObj  | 
1  | 
# validate.py
 | 
2  | 
# A Validator object
 | 
|
3  | 
# Copyright (C) 2005 Michael Foord, Mark Andrews, Nicola Larosa
 | 
|
4  | 
# E-mail: fuzzyman AT voidspace DOT org DOT uk
 | 
|
5  | 
#         mark AT la-la DOT com
 | 
|
6  | 
#         nico AT tekNico DOT net
 | 
|
7  | 
||
8  | 
# This software is licensed under the terms of the BSD license.
 | 
|
9  | 
# http://www.voidspace.org.uk/documents/BSD-LICENSE.txt
 | 
|
10  | 
# Basically you're free to copy, modify, distribute and relicense it,
 | 
|
11  | 
# So long as you keep a copy of the license with it.
 | 
|
12  | 
||
13  | 
# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
 | 
|
14  | 
# For information about bugfixes, updates and support, please join the
 | 
|
15  | 
# ConfigObj mailing list:
 | 
|
16  | 
# http://lists.sourceforge.net/lists/listinfo/configobj-develop
 | 
|
17  | 
# Comments, suggestions and bug reports welcome.
 | 
|
18  | 
||
19  | 
"""
 | 
|
20  | 
    The Validator object is used to check that supplied values 
 | 
|
21  | 
    conform to a specification.
 | 
|
22  | 
    
 | 
|
23  | 
    The value can be supplied as a string - e.g. from a config file.
 | 
|
24  | 
    In this case the check will also *convert* the value to
 | 
|
25  | 
    the required type. This allows you to add validation
 | 
|
26  | 
    as a transparent layer to access data stored as strings.
 | 
|
27  | 
    The validation checks that the data is correct *and*
 | 
|
28  | 
    converts it to the expected type.
 | 
|
29  | 
    
 | 
|
30  | 
    Some standard checks are provided for basic data types.
 | 
|
31  | 
    Additional checks are easy to write. They can be
 | 
|
32  | 
    provided when the ``Validator`` is instantiated or
 | 
|
33  | 
    added afterwards.
 | 
|
34  | 
    
 | 
|
35  | 
    The standard functions work with the following basic data types :
 | 
|
36  | 
    
 | 
|
37  | 
    * integers
 | 
|
38  | 
    * floats
 | 
|
39  | 
    * booleans
 | 
|
40  | 
    * strings
 | 
|
41  | 
    * ip_addr
 | 
|
42  | 
    
 | 
|
43  | 
    plus lists of these datatypes
 | 
|
44  | 
    
 | 
|
45  | 
    Adding additional checks is done through coding simple functions.
 | 
|
46  | 
    
 | 
|
47  | 
    The full set of standard checks are : 
 | 
|
48  | 
    
 | 
|
49  | 
    * 'integer': matches integer values (including negative)
 | 
|
50  | 
                 Takes optional 'min' and 'max' arguments : ::
 | 
|
51  | 
    
 | 
|
52  | 
                   integer()
 | 
|
53  | 
                   integer(3, 9)  # any value from 3 to 9
 | 
|
54  | 
                   integer(min=0) # any positive value
 | 
|
55  | 
                   integer(max=9)
 | 
|
56  | 
    
 | 
|
57  | 
    * 'float': matches float values
 | 
|
58  | 
               Has the same parameters as the integer check.
 | 
|
59  | 
    
 | 
|
60  | 
    * 'boolean': matches boolean values - ``True`` or ``False``
 | 
|
61  | 
                 Acceptable string values for True are :
 | 
|
62  | 
                   true, on, yes, 1
 | 
|
63  | 
                 Acceptable string values for False are :
 | 
|
64  | 
                   false, off, no, 0
 | 
|
65  | 
    
 | 
|
66  | 
                 Any other value raises an error.
 | 
|
67  | 
    
 | 
|
68  | 
    * 'ip_addr': matches an Internet Protocol address, v.4, represented
 | 
|
69  | 
                 by a dotted-quad string, i.e. '1.2.3.4'.
 | 
|
70  | 
    
 | 
|
71  | 
    * 'string': matches any string.
 | 
|
72  | 
                Takes optional keyword args 'min' and 'max'
 | 
|
73  | 
                to specify min and max lengths of the string.
 | 
|
74  | 
    
 | 
|
75  | 
    * 'list': matches any list.
 | 
|
76  | 
              Takes optional keyword args 'min', and 'max' to specify min and
 | 
|
77  | 
              max sizes of the list.
 | 
|
78  | 
    
 | 
|
79  | 
    * 'int_list': Matches a list of integers.
 | 
|
80  | 
                  Takes the same arguments as list.
 | 
|
81  | 
    
 | 
|
82  | 
    * 'float_list': Matches a list of floats.
 | 
|
83  | 
                    Takes the same arguments as list.
 | 
|
84  | 
    
 | 
|
85  | 
    * 'bool_list': Matches a list of boolean values.
 | 
|
86  | 
                   Takes the same arguments as list.
 | 
|
87  | 
    
 | 
|
88  | 
    * 'ip_addr_list': Matches a list of IP addresses.
 | 
|
89  | 
                     Takes the same arguments as list.
 | 
|
90  | 
    
 | 
|
91  | 
    * 'string_list': Matches a list of strings.
 | 
|
92  | 
                     Takes the same arguments as list.
 | 
|
93  | 
    
 | 
|
94  | 
    * 'mixed_list': Matches a list with different types in 
 | 
|
95  | 
                    specific positions. List size must match
 | 
|
96  | 
                    the number of arguments.
 | 
|
97  | 
    
 | 
|
98  | 
                    Each position can be one of :
 | 
|
99  | 
                    'integer', 'float', 'ip_addr', 'string', 'boolean'
 | 
|
100  | 
    
 | 
|
101  | 
                    So to specify a list with two strings followed
 | 
|
102  | 
                    by two integers, you write the check as : ::
 | 
|
103  | 
    
 | 
|
104  | 
                      mixed_list('string', 'string', 'integer', 'integer')
 | 
|
105  | 
    
 | 
|
106  | 
    * 'pass': This check matches everything ! It never fails
 | 
|
107  | 
              and the value is unchanged.
 | 
|
108  | 
    
 | 
|
109  | 
              It is also the default if no check is specified.
 | 
|
110  | 
    
 | 
|
111  | 
    * 'option': This check matches any from a list of options.
 | 
|
112  | 
                You specify this check with : ::
 | 
|
113  | 
    
 | 
|
114  | 
                  option('option 1', 'option 2', 'option 3')
 | 
|
115  | 
"""
 | 
|
116  | 
||
117  | 
__docformat__ = "restructuredtext en"  | 
|
118  | 
||
119  | 
__version__ = '0.2.0'  | 
|
120  | 
||
121  | 
__revision__ = '$Id: validate.py 123 2005-09-08 08:54:28Z fuzzyman $'  | 
|
122  | 
||
123  | 
__all__ = (  | 
|
124  | 
'__version__',  | 
|
125  | 
'dottedQuadToNum',  | 
|
126  | 
'numToDottedQuad',  | 
|
127  | 
'ValidateError',  | 
|
128  | 
'VdtUnknownCheckError',  | 
|
129  | 
'VdtParamError',  | 
|
130  | 
'VdtTypeError',  | 
|
131  | 
'VdtValueError',  | 
|
132  | 
'VdtValueTooSmallError',  | 
|
133  | 
'VdtValueTooBigError',  | 
|
134  | 
'VdtValueTooShortError',  | 
|
135  | 
'VdtValueTooLongError',  | 
|
136  | 
'VdtMissingValue',  | 
|
137  | 
'Validator',  | 
|
138  | 
'is_integer',  | 
|
139  | 
'is_float',  | 
|
140  | 
'is_bool',  | 
|
141  | 
'is_list',  | 
|
142  | 
'is_ip_addr',  | 
|
143  | 
'is_string',  | 
|
144  | 
'is_int_list',  | 
|
145  | 
'is_bool_list',  | 
|
146  | 
'is_float_list',  | 
|
147  | 
'is_string_list',  | 
|
148  | 
'is_ip_addr_list',  | 
|
149  | 
'is_mixed_list',  | 
|
150  | 
'is_option',  | 
|
151  | 
'__docformat__',  | 
|
152  | 
)
 | 
|
153  | 
||
154  | 
import sys  | 
|
155  | 
INTP_VER = sys.version_info[:2]  | 
|
156  | 
if INTP_VER < (2, 2):  | 
|
157  | 
raise RuntimeError("Python v.2.2 or later needed")  | 
|
158  | 
||
159  | 
import re  | 
|
160  | 
StringTypes = (str, unicode)  | 
|
161  | 
||
162  | 
# Python pre 2.2.1 doesn't have bool
 | 
|
163  | 
try:  | 
|
164  | 
    bool
 | 
|
165  | 
except NameError:  | 
|
166  | 
def bool(val):  | 
|
167  | 
"""Simple boolean equivalent function. """  | 
|
168  | 
if val:  | 
|
169  | 
return 1  | 
|
170  | 
else:  | 
|
171  | 
return 0  | 
|
172  | 
||
173  | 
def dottedQuadToNum(ip):  | 
|
174  | 
"""  | 
|
175  | 
    Convert decimal dotted quad string to long integer
 | 
|
176  | 
    
 | 
|
177  | 
    >>> dottedQuadToNum('1 ')
 | 
|
178  | 
    1L
 | 
|
179  | 
    >>> dottedQuadToNum(' 1.2')
 | 
|
180  | 
    16777218L
 | 
|
181  | 
    >>> dottedQuadToNum(' 1.2.3 ')
 | 
|
182  | 
    16908291L
 | 
|
183  | 
    >>> dottedQuadToNum('1.2.3.4')
 | 
|
184  | 
    16909060L
 | 
|
185  | 
    >>> dottedQuadToNum('1.2.3. 4')
 | 
|
186  | 
    Traceback (most recent call last):
 | 
|
187  | 
    ValueError: Not a good dotted-quad IP: 1.2.3. 4
 | 
|
188  | 
    >>> dottedQuadToNum('255.255.255.255')
 | 
|
189  | 
    4294967295L
 | 
|
190  | 
    >>> dottedQuadToNum('255.255.255.256')
 | 
|
191  | 
    Traceback (most recent call last):
 | 
|
192  | 
    ValueError: Not a good dotted-quad IP: 255.255.255.256
 | 
|
193  | 
    """
 | 
|
194  | 
||
195  | 
    # import here to avoid it when ip_addr values are not used
 | 
|
196  | 
import socket, struct  | 
|
197  | 
||
198  | 
try:  | 
|
199  | 
return struct.unpack('!L',  | 
|
200  | 
socket.inet_aton(ip.strip()))[0]  | 
|
201  | 
except socket.error:  | 
|
202  | 
        # bug in inet_aton, corrected in Python 2.3
 | 
|
203  | 
if ip.strip() == '255.255.255.255':  | 
|
204  | 
return 0xFFFFFFFFL  | 
|
205  | 
else:  | 
|
206  | 
raise ValueError('Not a good dotted-quad IP: %s' % ip)  | 
|
207  | 
    return
 | 
|
208  | 
||
209  | 
def numToDottedQuad(num):  | 
|
210  | 
"""  | 
|
211  | 
    Convert long int to dotted quad string
 | 
|
212  | 
    
 | 
|
213  | 
    >>> numToDottedQuad(-1L)
 | 
|
214  | 
    Traceback (most recent call last):
 | 
|
215  | 
    ValueError: Not a good numeric IP: -1
 | 
|
216  | 
    >>> numToDottedQuad(1L)
 | 
|
217  | 
    '0.0.0.1'
 | 
|
218  | 
    >>> numToDottedQuad(16777218L)
 | 
|
219  | 
    '1.0.0.2'
 | 
|
220  | 
    >>> numToDottedQuad(16908291L)
 | 
|
221  | 
    '1.2.0.3'
 | 
|
222  | 
    >>> numToDottedQuad(16909060L)
 | 
|
223  | 
    '1.2.3.4'
 | 
|
224  | 
    >>> numToDottedQuad(4294967295L)
 | 
|
225  | 
    '255.255.255.255'
 | 
|
226  | 
    >>> numToDottedQuad(4294967296L)
 | 
|
227  | 
    Traceback (most recent call last):
 | 
|
228  | 
    ValueError: Not a good numeric IP: 4294967296
 | 
|
229  | 
    """
 | 
|
230  | 
||
231  | 
    # import here to avoid it when ip_addr values are not used
 | 
|
232  | 
import socket, struct  | 
|
233  | 
||
234  | 
    # no need to intercept here, 4294967295L is fine
 | 
|
235  | 
try:  | 
|
236  | 
return socket.inet_ntoa(  | 
|
237  | 
struct.pack('!L', long(num)))  | 
|
238  | 
except (socket.error, struct.error, OverflowError):  | 
|
239  | 
raise ValueError('Not a good numeric IP: %s' % num)  | 
|
240  | 
||
241  | 
class ValidateError(Exception):  | 
|
242  | 
"""  | 
|
243  | 
    This error indicates that the check failed.
 | 
|
244  | 
    It can be the base class for more specific errors.
 | 
|
245  | 
    
 | 
|
246  | 
    Any check function that fails ought to raise this error.
 | 
|
247  | 
    (or a subclass)
 | 
|
248  | 
    
 | 
|
249  | 
    >>> raise ValidateError
 | 
|
250  | 
    Traceback (most recent call last):
 | 
|
251  | 
    ValidateError
 | 
|
252  | 
    """
 | 
|
253  | 
||
254  | 
class VdtMissingValue(ValidateError):  | 
|
255  | 
"""No value was supplied to a check that needed one."""  | 
|
256  | 
||
257  | 
class VdtUnknownCheckError(ValidateError):  | 
|
258  | 
"""An unknown check function was requested"""  | 
|
259  | 
||
260  | 
def __init__(self, value):  | 
|
261  | 
"""  | 
|
262  | 
        >>> raise VdtUnknownCheckError('yoda')
 | 
|
263  | 
        Traceback (most recent call last):
 | 
|
264  | 
        VdtUnknownCheckError: the check "yoda" is unknown.
 | 
|
265  | 
        """
 | 
|
266  | 
ValidateError.__init__(  | 
|
267  | 
self,  | 
|
268  | 
'the check "%s" is unknown.' % value)  | 
|
269  | 
||
270  | 
class VdtParamError(SyntaxError):  | 
|
271  | 
"""An incorrect parameter was passed"""  | 
|
272  | 
||
273  | 
def __init__(self, name, value):  | 
|
274  | 
"""  | 
|
275  | 
        >>> raise VdtParamError('yoda', 'jedi')
 | 
|
276  | 
        Traceback (most recent call last):
 | 
|
277  | 
        VdtParamError: passed an incorrect value "jedi" for parameter "yoda".
 | 
|
278  | 
        """
 | 
|
279  | 
SyntaxError.__init__(  | 
|
280  | 
self,  | 
|
281  | 
'passed an incorrect value "%s" for parameter "%s".' % (  | 
|
282  | 
value, name))  | 
|
283  | 
||
284  | 
class VdtTypeError(ValidateError):  | 
|
285  | 
"""The value supplied was of the wrong type"""  | 
|
286  | 
||
287  | 
def __init__(self, value):  | 
|
288  | 
"""  | 
|
289  | 
        >>> raise VdtTypeError('jedi')
 | 
|
290  | 
        Traceback (most recent call last):
 | 
|
291  | 
        VdtTypeError: the value "jedi" is of the wrong type.
 | 
|
292  | 
        """
 | 
|
293  | 
ValidateError.__init__(  | 
|
294  | 
self,  | 
|
295  | 
'the value "%s" is of the wrong type.' % value)  | 
|
296  | 
||
297  | 
class VdtValueError(ValidateError):  | 
|
298  | 
"""  | 
|
299  | 
    The value supplied was of the correct type, but was not an allowed value.
 | 
|
300  | 
    """
 | 
|
301  | 
||
302  | 
def __init__(self, value):  | 
|
303  | 
"""  | 
|
304  | 
        >>> raise VdtValueError('jedi')
 | 
|
305  | 
        Traceback (most recent call last):
 | 
|
306  | 
        VdtValueError: the value "jedi" is unacceptable.
 | 
|
307  | 
        """
 | 
|
308  | 
ValidateError.__init__(  | 
|
309  | 
self,  | 
|
310  | 
'the value "%s" is unacceptable.' % value)  | 
|
311  | 
||
312  | 
class VdtValueTooSmallError(VdtValueError):  | 
|
313  | 
"""The value supplied was of the correct type, but was too small."""  | 
|
314  | 
||
315  | 
def __init__(self, value):  | 
|
316  | 
"""  | 
|
317  | 
        >>> raise VdtValueTooSmallError('0')
 | 
|
318  | 
        Traceback (most recent call last):
 | 
|
319  | 
        VdtValueTooSmallError: the value "0" is too small.
 | 
|
320  | 
        """
 | 
|
321  | 
ValidateError.__init__(  | 
|
322  | 
self,  | 
|
323  | 
'the value "%s" is too small.' % value)  | 
|
324  | 
||
325  | 
class VdtValueTooBigError(VdtValueError):  | 
|
326  | 
"""The value supplied was of the correct type, but was too big."""  | 
|
327  | 
||
328  | 
def __init__(self, value):  | 
|
329  | 
"""  | 
|
330  | 
        >>> raise VdtValueTooBigError('1')
 | 
|
331  | 
        Traceback (most recent call last):
 | 
|
332  | 
        VdtValueTooBigError: the value "1" is too big.
 | 
|
333  | 
        """
 | 
|
334  | 
ValidateError.__init__(  | 
|
335  | 
self,  | 
|
336  | 
'the value "%s" is too big.' % value)  | 
|
337  | 
||
338  | 
class VdtValueTooShortError(VdtValueError):  | 
|
339  | 
"""The value supplied was of the correct type, but was too short."""  | 
|
340  | 
||
341  | 
def __init__(self, value):  | 
|
342  | 
"""  | 
|
343  | 
        >>> raise VdtValueTooShortError('jed')
 | 
|
344  | 
        Traceback (most recent call last):
 | 
|
345  | 
        VdtValueTooShortError: the value "jed" is too short.
 | 
|
346  | 
        """
 | 
|
347  | 
ValidateError.__init__(  | 
|
348  | 
self,  | 
|
349  | 
'the value "%s" is too short.' % (value,))  | 
|
350  | 
||
351  | 
class VdtValueTooLongError(VdtValueError):  | 
|
352  | 
"""The value supplied was of the correct type, but was too long."""  | 
|
353  | 
||
354  | 
def __init__(self, value):  | 
|
355  | 
"""  | 
|
356  | 
        >>> raise VdtValueTooLongError('jedie')
 | 
|
357  | 
        Traceback (most recent call last):
 | 
|
358  | 
        VdtValueTooLongError: the value "jedie" is too long.
 | 
|
359  | 
        """
 | 
|
360  | 
ValidateError.__init__(  | 
|
361  | 
self,  | 
|
362  | 
'the value "%s" is too long.' % (value,))  | 
|
363  | 
||
364  | 
class Validator(object):  | 
|
365  | 
"""  | 
|
366  | 
        Validator is an object that allows you to register a set of 'checks'.
 | 
|
367  | 
        These checks take input and test that it conforms to the check.
 | 
|
368  | 
        
 | 
|
369  | 
        This can also involve converting the value from a string into
 | 
|
370  | 
        the correct datatype.
 | 
|
371  | 
        
 | 
|
372  | 
        The ``check`` method takes an input string which configures which
 | 
|
373  | 
        check is to be used and applies that check to a supplied value.
 | 
|
374  | 
        
 | 
|
375  | 
        An example input string would be:
 | 
|
376  | 
        'int_range(param1, param2)'
 | 
|
377  | 
        
 | 
|
378  | 
        You would then provide something like:
 | 
|
379  | 
        
 | 
|
380  | 
        >>> def int_range_check(value, min, max):
 | 
|
381  | 
        ...     # turn min and max from strings to integers
 | 
|
382  | 
        ...     min = int(min)
 | 
|
383  | 
        ...     max = int(max)
 | 
|
384  | 
        ...     # check that value is of the correct type.
 | 
|
385  | 
        ...     # possible valid inputs are integers or strings
 | 
|
386  | 
        ...     # that represent integers
 | 
|
387  | 
        ...     if not isinstance(value, (int, long, StringTypes)):
 | 
|
388  | 
        ...         raise VdtTypeError(value)
 | 
|
389  | 
        ...     elif isinstance(value, StringTypes):
 | 
|
390  | 
        ...         # if we are given a string
 | 
|
391  | 
        ...         # attempt to convert to an integer
 | 
|
392  | 
        ...         try:
 | 
|
393  | 
        ...             value = int(value)
 | 
|
394  | 
        ...         except ValueError:
 | 
|
395  | 
        ...             raise VdtValueError(value)
 | 
|
396  | 
        ...     # check the value is between our constraints
 | 
|
397  | 
        ...     if not min <= value:
 | 
|
398  | 
        ...          raise VdtValueTooSmallError(value)
 | 
|
399  | 
        ...     if not value <= max:
 | 
|
400  | 
        ...          raise VdtValueTooBigError(value)
 | 
|
401  | 
        ...     return value
 | 
|
402  | 
        
 | 
|
403  | 
        >>> fdict = {'int_range': int_range_check}
 | 
|
404  | 
        >>> vtr1 = Validator(fdict)
 | 
|
405  | 
        >>> vtr1.check('int_range(20, 40)', '30')
 | 
|
406  | 
        30
 | 
|
407  | 
        >>> vtr1.check('int_range(20, 40)', '60')
 | 
|
408  | 
        Traceback (most recent call last):
 | 
|
409  | 
        VdtValueTooBigError: the value "60" is too big.
 | 
|
410  | 
        
 | 
|
411  | 
        New functions can be added with : ::
 | 
|
412  | 
        
 | 
|
413  | 
        >>> vtr2 = Validator()       
 | 
|
414  | 
        >>> vtr2.functions['int_range'] = int_range_check
 | 
|
415  | 
        
 | 
|
416  | 
        Or by passing in a dictionary of functions when Validator 
 | 
|
417  | 
        is instantiated.
 | 
|
418  | 
        
 | 
|
419  | 
        Your functions *can* use keyword arguments,
 | 
|
420  | 
        but the first argument should always be 'value'.
 | 
|
421  | 
        
 | 
|
422  | 
        If the function doesn't take additional arguments,
 | 
|
423  | 
        the parentheses are optional in the check.
 | 
|
424  | 
        It can be written with either of : ::
 | 
|
425  | 
        
 | 
|
426  | 
            keyword = function_name
 | 
|
427  | 
            keyword = function_name()
 | 
|
428  | 
        
 | 
|
429  | 
        The first program to utilise Validator() was Michael Foord's
 | 
|
430  | 
        ConfigObj, an alternative to ConfigParser which supports lists and
 | 
|
431  | 
        can validate a config file using a config schema.
 | 
|
432  | 
        For more details on using Validator with ConfigObj see:
 | 
|
433  | 
        http://www.voidspace.org.uk/python/configobj.html
 | 
|
434  | 
    """
 | 
|
435  | 
||
436  | 
    # this regex pulls values out of a comma separated line
 | 
|
437  | 
_paramfinder = re.compile(r'''(?:'.*?')|(?:".*?")|(?:[^'",\s][^,]*)''')  | 
|
438  | 
    # this regex is used for finding keyword arguments
 | 
|
439  | 
_key_arg = re.compile(r'^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.*)$')  | 
|
440  | 
    # this regex does the initial parsing of the checks
 | 
|
441  | 
_func_re = re.compile(r'(.+?)\((.*)\)')  | 
|
442  | 
||
443  | 
def __init__(self, functions=None):  | 
|
444  | 
"""  | 
|
445  | 
        >>> vtri = Validator()
 | 
|
446  | 
        """
 | 
|
447  | 
self.functions = {  | 
|
448  | 
'': self._pass,  | 
|
449  | 
'integer': is_integer,  | 
|
450  | 
'float': is_float,  | 
|
451  | 
'boolean': is_bool,  | 
|
452  | 
'ip_addr': is_ip_addr,  | 
|
453  | 
'string': is_string,  | 
|
454  | 
'list': is_list,  | 
|
455  | 
'int_list': is_int_list,  | 
|
456  | 
'float_list': is_float_list,  | 
|
457  | 
'bool_list': is_bool_list,  | 
|
458  | 
'ip_addr_list': is_ip_addr_list,  | 
|
459  | 
'string_list': is_string_list,  | 
|
460  | 
'mixed_list': is_mixed_list,  | 
|
461  | 
'pass': self._pass,  | 
|
462  | 
'option': is_option,  | 
|
463  | 
        }
 | 
|
464  | 
if functions is not None:  | 
|
465  | 
self.functions.update(functions)  | 
|
466  | 
        # tekNico: for use by ConfigObj
 | 
|
467  | 
self.baseErrorClass = ValidateError  | 
|
468  | 
||
469  | 
def check(self, check, value, missing=False):  | 
|
470  | 
"""  | 
|
471  | 
        Usage: check(check, value)
 | 
|
472  | 
        
 | 
|
473  | 
        Arguments:
 | 
|
474  | 
            check: string representing check to apply (including arguments)
 | 
|
475  | 
            value: object to be checked
 | 
|
476  | 
        Returns value, converted to correct type if necessary
 | 
|
477  | 
        
 | 
|
478  | 
        If the check fails, raises a ``ValidateError`` subclass.
 | 
|
479  | 
        
 | 
|
480  | 
        >>> vtor.check('yoda', '')
 | 
|
481  | 
        Traceback (most recent call last):
 | 
|
482  | 
        VdtUnknownCheckError: the check "yoda" is unknown.
 | 
|
483  | 
        >>> vtor.check('yoda()', '')
 | 
|
484  | 
        Traceback (most recent call last):
 | 
|
485  | 
        VdtUnknownCheckError: the check "yoda" is unknown.
 | 
|
486  | 
        """
 | 
|
487  | 
fun_match = self._func_re.match(check)  | 
|
488  | 
if fun_match:  | 
|
489  | 
fun_name = fun_match.group(1)  | 
|
490  | 
fun_args = []  | 
|
491  | 
fun_kwargs = {}  | 
|
492  | 
            # pull out args of group 2
 | 
|
493  | 
for arg in self._paramfinder.findall(fun_match.group(2)):  | 
|
494  | 
                # args may need whitespace removing (before removing quotes)
 | 
|
495  | 
arg = arg.strip()  | 
|
496  | 
keymatch = self._key_arg.match(arg)  | 
|
497  | 
if keymatch:  | 
|
498  | 
val = keymatch.group(2)  | 
|
499  | 
if (val[0] in ("'", '"')) and (val[0] == val[-1]):  | 
|
500  | 
val = val[1:-1]  | 
|
501  | 
fun_kwargs[keymatch.group(1)] = val  | 
|
502  | 
                    continue
 | 
|
503  | 
                #
 | 
|
504  | 
if (arg[0] in ("'", '"')) and (arg[0] == arg[-1]):  | 
|
505  | 
arg = arg[1:-1]  | 
|
506  | 
fun_args.append(arg)  | 
|
507  | 
else:  | 
|
508  | 
            # allows for function names without (args)
 | 
|
509  | 
(fun_name, fun_args, fun_kwargs) = (check, (), {})  | 
|
510  | 
        #
 | 
|
511  | 
if missing:  | 
|
512  | 
try:  | 
|
513  | 
value = fun_kwargs['default']  | 
|
514  | 
except KeyError:  | 
|
515  | 
raise VdtMissingValue  | 
|
516  | 
if value == 'None':  | 
|
517  | 
value = None  | 
|
518  | 
if value is None:  | 
|
519  | 
return None  | 
|
520  | 
# tekNico: default must be deleted if the value is specified too,
 | 
|
521  | 
# otherwise the check function will get a spurious "default" keyword arg
 | 
|
522  | 
try:  | 
|
523  | 
del fun_kwargs['default']  | 
|
524  | 
except KeyError:  | 
|
525  | 
            pass
 | 
|
526  | 
try:  | 
|
527  | 
return self.functions[fun_name](value, *fun_args, **fun_kwargs)  | 
|
528  | 
except KeyError:  | 
|
529  | 
raise VdtUnknownCheckError(fun_name)  | 
|
530  | 
||
531  | 
def _pass(self, value):  | 
|
532  | 
"""  | 
|
533  | 
        Dummy check that always passes
 | 
|
534  | 
        
 | 
|
535  | 
        >>> vtor.check('', 0)
 | 
|
536  | 
        0
 | 
|
537  | 
        >>> vtor.check('', '0')
 | 
|
538  | 
        '0'
 | 
|
539  | 
        """
 | 
|
540  | 
return value  | 
|
541  | 
||
542  | 
||
543  | 
def _is_num_param(names, values, to_float=False):  | 
|
544  | 
"""  | 
|
545  | 
    Return numbers from inputs or raise VdtParamError.
 | 
|
546  | 
    
 | 
|
547  | 
    Lets ``None`` pass through.
 | 
|
548  | 
    Pass in keyword argument ``to_float=True`` to
 | 
|
549  | 
    use float for the conversion rather than int.
 | 
|
550  | 
    
 | 
|
551  | 
    >>> _is_num_param(('', ''), (0, 1.0))
 | 
|
552  | 
    [0, 1]
 | 
|
553  | 
    >>> _is_num_param(('', ''), (0, 1.0), to_float=True)
 | 
|
554  | 
    [0.0, 1.0]
 | 
|
555  | 
    >>> _is_num_param(('a'), ('a'))
 | 
|
556  | 
    Traceback (most recent call last):
 | 
|
557  | 
    VdtParamError: passed an incorrect value "a" for parameter "a".
 | 
|
558  | 
    """
 | 
|
559  | 
fun = to_float and float or int  | 
|
560  | 
out_params = []  | 
|
561  | 
for (name, val) in zip(names, values):  | 
|
562  | 
if val is None:  | 
|
563  | 
out_params.append(val)  | 
|
564  | 
elif isinstance(val, (int, long, float, StringTypes)):  | 
|
565  | 
try:  | 
|
566  | 
out_params.append(fun(val))  | 
|
567  | 
except ValueError, e:  | 
|
568  | 
raise VdtParamError(name, val)  | 
|
569  | 
else:  | 
|
570  | 
raise VdtParamError(name, val)  | 
|
571  | 
return out_params  | 
|
572  | 
||
573  | 
# built in checks
 | 
|
574  | 
# you can override these by setting the appropriate name
 | 
|
575  | 
# in Validator.functions
 | 
|
576  | 
# note: if the params are specified wrongly in your input string,
 | 
|
577  | 
#       you will also raise errors.
 | 
|
578  | 
||
579  | 
def is_integer(value, min=None, max=None):  | 
|
580  | 
"""  | 
|
581  | 
    A check that tests that a given value is an integer (int, or long)
 | 
|
582  | 
    and optionally, between bounds. A negative value is accepted, while
 | 
|
583  | 
    a float will fail.
 | 
|
584  | 
    
 | 
|
585  | 
    If the value is a string, then the conversion is done - if possible.
 | 
|
586  | 
    Otherwise a VdtError is raised.
 | 
|
587  | 
    
 | 
|
588  | 
    >>> vtor.check('integer', '-1')
 | 
|
589  | 
    -1
 | 
|
590  | 
    >>> vtor.check('integer', '0')
 | 
|
591  | 
    0
 | 
|
592  | 
    >>> vtor.check('integer', 9)
 | 
|
593  | 
    9
 | 
|
594  | 
    >>> vtor.check('integer', 'a')
 | 
|
595  | 
    Traceback (most recent call last):
 | 
|
596  | 
    VdtTypeError: the value "a" is of the wrong type.
 | 
|
597  | 
    >>> vtor.check('integer', '2.2')
 | 
|
598  | 
    Traceback (most recent call last):
 | 
|
599  | 
    VdtTypeError: the value "2.2" is of the wrong type.
 | 
|
600  | 
    >>> vtor.check('integer(10)', '20')
 | 
|
601  | 
    20
 | 
|
602  | 
    >>> vtor.check('integer(max=20)', '15')
 | 
|
603  | 
    15
 | 
|
604  | 
    >>> vtor.check('integer(10)', '9')
 | 
|
605  | 
    Traceback (most recent call last):
 | 
|
606  | 
    VdtValueTooSmallError: the value "9" is too small.
 | 
|
607  | 
    >>> vtor.check('integer(10)', 9)
 | 
|
608  | 
    Traceback (most recent call last):
 | 
|
609  | 
    VdtValueTooSmallError: the value "9" is too small.
 | 
|
610  | 
    >>> vtor.check('integer(max=20)', '35')
 | 
|
611  | 
    Traceback (most recent call last):
 | 
|
612  | 
    VdtValueTooBigError: the value "35" is too big.
 | 
|
613  | 
    >>> vtor.check('integer(max=20)', 35)
 | 
|
614  | 
    Traceback (most recent call last):
 | 
|
615  | 
    VdtValueTooBigError: the value "35" is too big.
 | 
|
616  | 
    >>> vtor.check('integer(0, 9)', False)
 | 
|
617  | 
    0
 | 
|
618  | 
    """
 | 
|
619  | 
#    print value, type(value)
 | 
|
620  | 
(min_val, max_val) = _is_num_param(('min', 'max'), (min, max))  | 
|
621  | 
if not isinstance(value, (int, long, StringTypes)):  | 
|
622  | 
raise VdtTypeError(value)  | 
|
623  | 
if isinstance(value, StringTypes):  | 
|
624  | 
        # if it's a string - does it represent an integer ?
 | 
|
625  | 
try:  | 
|
626  | 
value = int(value)  | 
|
627  | 
except ValueError:  | 
|
628  | 
raise VdtTypeError(value)  | 
|
629  | 
if (min_val is not None) and (value < min_val):  | 
|
630  | 
raise VdtValueTooSmallError(value)  | 
|
631  | 
if (max_val is not None) and (value > max_val):  | 
|
632  | 
raise VdtValueTooBigError(value)  | 
|
633  | 
return value  | 
|
634  | 
||
635  | 
def is_float(value, min=None, max=None):  | 
|
636  | 
"""  | 
|
637  | 
    A check that tests that a given value is a float
 | 
|
638  | 
    (an integer will be accepted), and optionally - that it is between bounds.
 | 
|
639  | 
    
 | 
|
640  | 
    If the value is a string, then the conversion is done - if possible.
 | 
|
641  | 
    Otherwise a VdtError is raised.
 | 
|
642  | 
    
 | 
|
643  | 
    This can accept negative values.
 | 
|
644  | 
    
 | 
|
645  | 
    >>> vtor.check('float', '2')
 | 
|
646  | 
    2.0
 | 
|
647  | 
    
 | 
|
648  | 
    From now on we multiply the value to avoid comparing decimals
 | 
|
649  | 
    
 | 
|
650  | 
    >>> vtor.check('float', '-6.8') * 10
 | 
|
651  | 
    -68.0
 | 
|
652  | 
    >>> vtor.check('float', '12.2') * 10
 | 
|
653  | 
    122.0
 | 
|
654  | 
    >>> vtor.check('float', 8.4) * 10
 | 
|
655  | 
    84.0
 | 
|
656  | 
    >>> vtor.check('float', 'a')
 | 
|
657  | 
    Traceback (most recent call last):
 | 
|
658  | 
    VdtTypeError: the value "a" is of the wrong type.
 | 
|
659  | 
    >>> vtor.check('float(10.1)', '10.2') * 10
 | 
|
660  | 
    102.0
 | 
|
661  | 
    >>> vtor.check('float(max=20.2)', '15.1') * 10
 | 
|
662  | 
    151.0
 | 
|
663  | 
    >>> vtor.check('float(10.0)', '9.0')
 | 
|
664  | 
    Traceback (most recent call last):
 | 
|
665  | 
    VdtValueTooSmallError: the value "9.0" is too small.
 | 
|
666  | 
    >>> vtor.check('float(max=20.0)', '35.0')
 | 
|
667  | 
    Traceback (most recent call last):
 | 
|
668  | 
    VdtValueTooBigError: the value "35.0" is too big.
 | 
|
669  | 
    """
 | 
|
670  | 
(min_val, max_val) = _is_num_param(  | 
|
671  | 
('min', 'max'), (min, max), to_float=True)  | 
|
672  | 
if not isinstance(value, (int, long, float, StringTypes)):  | 
|
673  | 
raise VdtTypeError(value)  | 
|
674  | 
if not isinstance(value, float):  | 
|
675  | 
        # if it's a string - does it represent a float ?
 | 
|
676  | 
try:  | 
|
677  | 
value = float(value)  | 
|
678  | 
except ValueError:  | 
|
679  | 
raise VdtTypeError(value)  | 
|
680  | 
if (min_val is not None) and (value < min_val):  | 
|
681  | 
raise VdtValueTooSmallError(value)  | 
|
682  | 
if (max_val is not None) and (value > max_val):  | 
|
683  | 
raise VdtValueTooBigError(value)  | 
|
684  | 
return value  | 
|
685  | 
||
686  | 
bool_dict = {  | 
|
687  | 
True: True, 'on': True, '1': True, 'true': True, 'yes': True,  | 
|
688  | 
False: False, 'off': False, '0': False, 'false': False, 'no': False,  | 
|
689  | 
}
 | 
|
690  | 
||
691  | 
def is_bool(value):  | 
|
692  | 
"""  | 
|
693  | 
    Check if the value represents a boolean.
 | 
|
694  | 
    
 | 
|
695  | 
    >>> vtor.check('boolean', 0)
 | 
|
696  | 
    0
 | 
|
697  | 
    >>> vtor.check('boolean', False)
 | 
|
698  | 
    0
 | 
|
699  | 
    >>> vtor.check('boolean', '0')
 | 
|
700  | 
    0
 | 
|
701  | 
    >>> vtor.check('boolean', 'off')
 | 
|
702  | 
    0
 | 
|
703  | 
    >>> vtor.check('boolean', 'false')
 | 
|
704  | 
    0
 | 
|
705  | 
    >>> vtor.check('boolean', 'no')
 | 
|
706  | 
    0
 | 
|
707  | 
    >>> vtor.check('boolean', 'nO')
 | 
|
708  | 
    0
 | 
|
709  | 
    >>> vtor.check('boolean', 'NO')
 | 
|
710  | 
    0
 | 
|
711  | 
    >>> vtor.check('boolean', 1)
 | 
|
712  | 
    1
 | 
|
713  | 
    >>> vtor.check('boolean', True)
 | 
|
714  | 
    1
 | 
|
715  | 
    >>> vtor.check('boolean', '1')
 | 
|
716  | 
    1
 | 
|
717  | 
    >>> vtor.check('boolean', 'on')
 | 
|
718  | 
    1
 | 
|
719  | 
    >>> vtor.check('boolean', 'true')
 | 
|
720  | 
    1
 | 
|
721  | 
    >>> vtor.check('boolean', 'yes')
 | 
|
722  | 
    1
 | 
|
723  | 
    >>> vtor.check('boolean', 'Yes')
 | 
|
724  | 
    1
 | 
|
725  | 
    >>> vtor.check('boolean', 'YES')
 | 
|
726  | 
    1
 | 
|
727  | 
    >>> vtor.check('boolean', '')
 | 
|
728  | 
    Traceback (most recent call last):
 | 
|
729  | 
    VdtTypeError: the value "" is of the wrong type.
 | 
|
730  | 
    >>> vtor.check('boolean', 'up')
 | 
|
731  | 
    Traceback (most recent call last):
 | 
|
732  | 
    VdtTypeError: the value "up" is of the wrong type.
 | 
|
733  | 
    
 | 
|
734  | 
    """
 | 
|
735  | 
if isinstance(value, StringTypes):  | 
|
736  | 
try:  | 
|
737  | 
return bool_dict[value.lower()]  | 
|
738  | 
except KeyError:  | 
|
739  | 
raise VdtTypeError(value)  | 
|
740  | 
    # we do an equality test rather than an identity test
 | 
|
741  | 
    # this ensures Python 2.2 compatibilty
 | 
|
742  | 
    # and allows 0 and 1 to represent True and False
 | 
|
743  | 
if value == False:  | 
|
744  | 
return False  | 
|
745  | 
elif value == True:  | 
|
746  | 
return True  | 
|
747  | 
else:  | 
|
748  | 
raise VdtTypeError(value)  | 
|
749  | 
||
750  | 
||
751  | 
def is_ip_addr(value):  | 
|
752  | 
"""  | 
|
753  | 
    Check that the supplied value is an Internet Protocol address, v.4,
 | 
|
754  | 
    represented by a dotted-quad string, i.e. '1.2.3.4'.
 | 
|
755  | 
    
 | 
|
756  | 
    >>> vtor.check('ip_addr', '1 ')
 | 
|
757  | 
    '1'
 | 
|
758  | 
    >>> vtor.check('ip_addr', ' 1.2')
 | 
|
759  | 
    '1.2'
 | 
|
760  | 
    >>> vtor.check('ip_addr', ' 1.2.3 ')
 | 
|
761  | 
    '1.2.3'
 | 
|
762  | 
    >>> vtor.check('ip_addr', '1.2.3.4')
 | 
|
763  | 
    '1.2.3.4'
 | 
|
764  | 
    >>> vtor.check('ip_addr', '0.0.0.0')
 | 
|
765  | 
    '0.0.0.0'
 | 
|
766  | 
    >>> vtor.check('ip_addr', '255.255.255.255')
 | 
|
767  | 
    '255.255.255.255'
 | 
|
768  | 
    >>> vtor.check('ip_addr', '255.255.255.256')
 | 
|
769  | 
    Traceback (most recent call last):
 | 
|
770  | 
    VdtValueError: the value "255.255.255.256" is unacceptable.
 | 
|
771  | 
    >>> vtor.check('ip_addr', '1.2.3.4.5')
 | 
|
772  | 
    Traceback (most recent call last):
 | 
|
773  | 
    VdtValueError: the value "1.2.3.4.5" is unacceptable.
 | 
|
774  | 
    >>> vtor.check('ip_addr', '1.2.3. 4')
 | 
|
775  | 
    Traceback (most recent call last):
 | 
|
776  | 
    VdtValueError: the value "1.2.3. 4" is unacceptable.
 | 
|
777  | 
    >>> vtor.check('ip_addr', 0)
 | 
|
778  | 
    Traceback (most recent call last):
 | 
|
779  | 
    VdtTypeError: the value "0" is of the wrong type.
 | 
|
780  | 
    """
 | 
|
781  | 
if not isinstance(value, StringTypes):  | 
|
782  | 
raise VdtTypeError(value)  | 
|
783  | 
value = value.strip()  | 
|
784  | 
try:  | 
|
785  | 
dottedQuadToNum(value)  | 
|
786  | 
except ValueError:  | 
|
787  | 
raise VdtValueError(value)  | 
|
788  | 
return value  | 
|
789  | 
||
790  | 
def is_list(value, min=None, max=None):  | 
|
791  | 
"""  | 
|
792  | 
    Check that the value is a list of values.
 | 
|
793  | 
    
 | 
|
794  | 
    You can optionally specify the minimum and maximum number of members.
 | 
|
795  | 
    
 | 
|
796  | 
    It does no check on list members.
 | 
|
797  | 
    
 | 
|
798  | 
    >>> vtor.check('list', ())
 | 
|
799  | 
    ()
 | 
|
800  | 
    >>> vtor.check('list', [])
 | 
|
801  | 
    []
 | 
|
802  | 
    >>> vtor.check('list', (1, 2))
 | 
|
803  | 
    (1, 2)
 | 
|
804  | 
    >>> vtor.check('list', [1, 2])
 | 
|
805  | 
    [1, 2]
 | 
|
806  | 
    >>> vtor.check('list', '12')
 | 
|
807  | 
    '12'
 | 
|
808  | 
    >>> vtor.check('list(3)', (1, 2))
 | 
|
809  | 
    Traceback (most recent call last):
 | 
|
810  | 
    VdtValueTooShortError: the value "(1, 2)" is too short.
 | 
|
811  | 
    >>> vtor.check('list(max=5)', (1, 2, 3, 4, 5, 6))
 | 
|
812  | 
    Traceback (most recent call last):
 | 
|
813  | 
    VdtValueTooLongError: the value "(1, 2, 3, 4, 5, 6)" is too long.
 | 
|
814  | 
    >>> vtor.check('list(min=3, max=5)', (1, 2, 3, 4))
 | 
|
815  | 
    (1, 2, 3, 4)
 | 
|
816  | 
    >>> vtor.check('list', 0)
 | 
|
817  | 
    Traceback (most recent call last):
 | 
|
818  | 
    VdtTypeError: the value "0" is of the wrong type.
 | 
|
819  | 
    """
 | 
|
820  | 
(min_len, max_len) = _is_num_param(('min', 'max'), (min, max))  | 
|
821  | 
try:  | 
|
822  | 
num_members = len(value)  | 
|
823  | 
except TypeError:  | 
|
824  | 
raise VdtTypeError(value)  | 
|
825  | 
if min_len is not None and num_members < min_len:  | 
|
826  | 
raise VdtValueTooShortError(value)  | 
|
827  | 
if max_len is not None and num_members > max_len:  | 
|
828  | 
raise VdtValueTooLongError(value)  | 
|
829  | 
return value  | 
|
830  | 
||
831  | 
def is_string(value, min=None, max=None):  | 
|
832  | 
"""  | 
|
833  | 
    Check that the supplied value is a string.
 | 
|
834  | 
    
 | 
|
835  | 
    You can optionally specify the minimum and maximum number of members.
 | 
|
836  | 
    
 | 
|
837  | 
    >>> vtor.check('string', '0')
 | 
|
838  | 
    '0'
 | 
|
839  | 
    >>> vtor.check('string', 0)
 | 
|
840  | 
    Traceback (most recent call last):
 | 
|
841  | 
    VdtTypeError: the value "0" is of the wrong type.
 | 
|
842  | 
    >>> vtor.check('string(2)', '12')
 | 
|
843  | 
    '12'
 | 
|
844  | 
    >>> vtor.check('string(2)', '1')
 | 
|
845  | 
    Traceback (most recent call last):
 | 
|
846  | 
    VdtValueTooShortError: the value "1" is too short.
 | 
|
847  | 
    >>> vtor.check('string(min=2, max=3)', '123')
 | 
|
848  | 
    '123'
 | 
|
849  | 
    >>> vtor.check('string(min=2, max=3)', '1234')
 | 
|
850  | 
    Traceback (most recent call last):
 | 
|
851  | 
    VdtValueTooLongError: the value "1234" is too long.
 | 
|
852  | 
    """
 | 
|
853  | 
if not isinstance(value, StringTypes):  | 
|
854  | 
raise VdtTypeError(value)  | 
|
855  | 
return is_list(value, min, max)  | 
|
856  | 
||
857  | 
def is_int_list(value, min=None, max=None):  | 
|
858  | 
"""  | 
|
859  | 
    Check that the value is a list of integers.
 | 
|
860  | 
    
 | 
|
861  | 
    You can optionally specify the minimum and maximum number of members.
 | 
|
862  | 
    
 | 
|
863  | 
    Each list member is checked that it is an integer.
 | 
|
864  | 
    
 | 
|
865  | 
    >>> vtor.check('int_list', ())
 | 
|
866  | 
    []
 | 
|
867  | 
    >>> vtor.check('int_list', [])
 | 
|
868  | 
    []
 | 
|
869  | 
    >>> vtor.check('int_list', (1, 2))
 | 
|
870  | 
    [1, 2]
 | 
|
871  | 
    >>> vtor.check('int_list', [1, 2])
 | 
|
872  | 
    [1, 2]
 | 
|
873  | 
    >>> vtor.check('int_list', [1, 'a'])
 | 
|
874  | 
    Traceback (most recent call last):
 | 
|
875  | 
    VdtTypeError: the value "a" is of the wrong type.
 | 
|
876  | 
    """
 | 
|
877  | 
return [is_integer(mem) for mem in is_list(value, min, max)]  | 
|
878  | 
||
879  | 
def is_bool_list(value, min=None, max=None):  | 
|
880  | 
"""  | 
|
881  | 
    Check that the value is a list of booleans.
 | 
|
882  | 
    
 | 
|
883  | 
    You can optionally specify the minimum and maximum number of members.
 | 
|
884  | 
    
 | 
|
885  | 
    Each list member is checked that it is a boolean.
 | 
|
886  | 
    
 | 
|
887  | 
    >>> vtor.check('bool_list', ())
 | 
|
888  | 
    []
 | 
|
889  | 
    >>> vtor.check('bool_list', [])
 | 
|
890  | 
    []
 | 
|
891  | 
    >>> check_res = vtor.check('bool_list', (True, False))
 | 
|
892  | 
    >>> check_res == [True, False]
 | 
|
893  | 
    1
 | 
|
894  | 
    >>> check_res = vtor.check('bool_list', [True, False])
 | 
|
895  | 
    >>> check_res == [True, False]
 | 
|
896  | 
    1
 | 
|
897  | 
    >>> vtor.check('bool_list', [True, 'a'])
 | 
|
898  | 
    Traceback (most recent call last):
 | 
|
899  | 
    VdtTypeError: the value "a" is of the wrong type.
 | 
|
900  | 
    """
 | 
|
901  | 
return [is_bool(mem) for mem in is_list(value, min, max)]  | 
|
902  | 
||
903  | 
def is_float_list(value, min=None, max=None):  | 
|
904  | 
"""  | 
|
905  | 
    Check that the value is a list of floats.
 | 
|
906  | 
    
 | 
|
907  | 
    You can optionally specify the minimum and maximum number of members.
 | 
|
908  | 
    
 | 
|
909  | 
    Each list member is checked that it is a float.
 | 
|
910  | 
    
 | 
|
911  | 
    >>> vtor.check('float_list', ())
 | 
|
912  | 
    []
 | 
|
913  | 
    >>> vtor.check('float_list', [])
 | 
|
914  | 
    []
 | 
|
915  | 
    >>> vtor.check('float_list', (1, 2.0))
 | 
|
916  | 
    [1.0, 2.0]
 | 
|
917  | 
    >>> vtor.check('float_list', [1, 2.0])
 | 
|
918  | 
    [1.0, 2.0]
 | 
|
919  | 
    >>> vtor.check('float_list', [1, 'a'])
 | 
|
920  | 
    Traceback (most recent call last):
 | 
|
921  | 
    VdtTypeError: the value "a" is of the wrong type.
 | 
|
922  | 
    """
 | 
|
923  | 
return [is_float(mem) for mem in is_list(value, min, max)]  | 
|
924  | 
||
925  | 
def is_string_list(value, min=None, max=None):  | 
|
926  | 
"""  | 
|
927  | 
    Check that the value is a list of strings.
 | 
|
928  | 
    
 | 
|
929  | 
    You can optionally specify the minimum and maximum number of members.
 | 
|
930  | 
    
 | 
|
931  | 
    Each list member is checked that it is a string.
 | 
|
932  | 
    
 | 
|
933  | 
    >>> vtor.check('string_list', ())
 | 
|
934  | 
    []
 | 
|
935  | 
    >>> vtor.check('string_list', [])
 | 
|
936  | 
    []
 | 
|
937  | 
    >>> vtor.check('string_list', ('a', 'b'))
 | 
|
938  | 
    ['a', 'b']
 | 
|
939  | 
    >>> vtor.check('string_list', ['a', 1])
 | 
|
940  | 
    Traceback (most recent call last):
 | 
|
941  | 
    VdtTypeError: the value "1" is of the wrong type.
 | 
|
942  | 
    """
 | 
|
943  | 
return [is_string(mem) for mem in is_list(value, min, max)]  | 
|
944  | 
||
945  | 
def is_ip_addr_list(value, min=None, max=None):  | 
|
946  | 
"""  | 
|
947  | 
    Check that the value is a list of IP addresses.
 | 
|
948  | 
    
 | 
|
949  | 
    You can optionally specify the minimum and maximum number of members.
 | 
|
950  | 
    
 | 
|
951  | 
    Each list member is checked that it is an IP address.
 | 
|
952  | 
    
 | 
|
953  | 
    >>> vtor.check('ip_addr_list', ())
 | 
|
954  | 
    []
 | 
|
955  | 
    >>> vtor.check('ip_addr_list', [])
 | 
|
956  | 
    []
 | 
|
957  | 
    >>> vtor.check('ip_addr_list', ('1.2.3.4', '5.6.7.8'))
 | 
|
958  | 
    ['1.2.3.4', '5.6.7.8']
 | 
|
959  | 
    >>> vtor.check('ip_addr_list', ['a'])
 | 
|
960  | 
    Traceback (most recent call last):
 | 
|
961  | 
    VdtValueError: the value "a" is unacceptable.
 | 
|
962  | 
    """
 | 
|
963  | 
return [is_ip_addr(mem) for mem in is_list(value, min, max)]  | 
|
964  | 
||
965  | 
fun_dict = {  | 
|
966  | 
'integer': is_integer,  | 
|
967  | 
'float': is_float,  | 
|
968  | 
'ip_addr': is_ip_addr,  | 
|
969  | 
'string': is_string,  | 
|
970  | 
'boolean': is_bool,  | 
|
971  | 
}
 | 
|
972  | 
||
973  | 
def is_mixed_list(value, *args):  | 
|
974  | 
"""  | 
|
975  | 
    Check that the value is a list.
 | 
|
976  | 
    Allow specifying the type of each member.
 | 
|
977  | 
    Work on lists of specific lengths.
 | 
|
978  | 
    
 | 
|
979  | 
    You specify each member as a positional argument specifying type
 | 
|
980  | 
    
 | 
|
981  | 
    Each type should be one of the following strings :
 | 
|
982  | 
      'integer', 'float', 'ip_addr', 'string', 'boolean'
 | 
|
983  | 
    
 | 
|
984  | 
    So you can specify a list of two strings, followed by
 | 
|
985  | 
    two integers as :
 | 
|
986  | 
    
 | 
|
987  | 
      mixed_list('string', 'string', 'integer', 'integer')
 | 
|
988  | 
    
 | 
|
989  | 
    The length of the list must match the number of positional
 | 
|
990  | 
    arguments you supply.
 | 
|
991  | 
    
 | 
|
992  | 
    >>> mix_str = "mixed_list('integer', 'float', 'ip_addr', 'string', 'boolean')"
 | 
|
993  | 
    >>> check_res = vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', True))
 | 
|
994  | 
    >>> check_res == [1, 2.0, '1.2.3.4', 'a', True]
 | 
|
995  | 
    1
 | 
|
996  | 
    >>> check_res = vtor.check(mix_str, ('1', '2.0', '1.2.3.4', 'a', 'True'))
 | 
|
997  | 
    >>> check_res == [1, 2.0, '1.2.3.4', 'a', True]
 | 
|
998  | 
    1
 | 
|
999  | 
    >>> vtor.check(mix_str, ('b', 2.0, '1.2.3.4', 'a', True))
 | 
|
1000  | 
    Traceback (most recent call last):
 | 
|
1001  | 
    VdtTypeError: the value "b" is of the wrong type.
 | 
|
1002  | 
    >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a'))
 | 
|
1003  | 
    Traceback (most recent call last):
 | 
|
1004  | 
    VdtValueTooShortError: the value "(1, 2.0, '1.2.3.4', 'a')" is too short.
 | 
|
1005  | 
    >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', 1, 'b'))
 | 
|
1006  | 
    Traceback (most recent call last):
 | 
|
1007  | 
    VdtValueTooLongError: the value "(1, 2.0, '1.2.3.4', 'a', 1, 'b')" is too long.
 | 
|
1008  | 
    >>> vtor.check(mix_str, 0)
 | 
|
1009  | 
    Traceback (most recent call last):
 | 
|
1010  | 
    VdtTypeError: the value "0" is of the wrong type.
 | 
|
1011  | 
    
 | 
|
1012  | 
    This test requires an elaborate setup, because of a change in error string
 | 
|
1013  | 
    output from the interpreter between Python 2.2 and 2.3 .
 | 
|
1014  | 
    
 | 
|
1015  | 
    >>> res_seq = (
 | 
|
1016  | 
    ...     'passed an incorrect value "',
 | 
|
1017  | 
    ...     'yoda',
 | 
|
1018  | 
    ...     '" for parameter "mixed_list".',
 | 
|
1019  | 
    ... )
 | 
|
1020  | 
    >>> if INTP_VER == (2, 2):
 | 
|
1021  | 
    ...     res_str = "".join(res_seq)
 | 
|
1022  | 
    ... else:
 | 
|
1023  | 
    ...     res_str = "'".join(res_seq)
 | 
|
1024  | 
    >>> try:
 | 
|
1025  | 
    ...     vtor.check('mixed_list("yoda")', ('a'))
 | 
|
1026  | 
    ... except VdtParamError, err:
 | 
|
1027  | 
    ...     str(err) == res_str
 | 
|
1028  | 
    1
 | 
|
1029  | 
    """
 | 
|
1030  | 
try:  | 
|
1031  | 
length = len(value)  | 
|
1032  | 
except TypeError:  | 
|
1033  | 
raise VdtTypeError(value)  | 
|
1034  | 
if length < len(args):  | 
|
1035  | 
raise VdtValueTooShortError(value)  | 
|
1036  | 
elif length > len(args):  | 
|
1037  | 
raise VdtValueTooLongError(value)  | 
|
1038  | 
try:  | 
|
1039  | 
return [fun_dict[arg](val) for arg, val in zip(args, value)]  | 
|
1040  | 
except KeyError, e:  | 
|
1041  | 
raise VdtParamError('mixed_list', e)  | 
|
1042  | 
||
1043  | 
def is_option(value, *options):  | 
|
1044  | 
"""  | 
|
1045  | 
    This check matches the value to any of a set of options.
 | 
|
1046  | 
    
 | 
|
1047  | 
    >>> vtor.check('option("yoda", "jedi")', 'yoda')
 | 
|
1048  | 
    'yoda'
 | 
|
1049  | 
    >>> vtor.check('option("yoda", "jedi")', 'jed')
 | 
|
1050  | 
    Traceback (most recent call last):
 | 
|
1051  | 
    VdtValueError: the value "jed" is unacceptable.
 | 
|
1052  | 
    >>> vtor.check('option("yoda", "jedi")', 0)
 | 
|
1053  | 
    Traceback (most recent call last):
 | 
|
1054  | 
    VdtTypeError: the value "0" is of the wrong type.
 | 
|
1055  | 
    """
 | 
|
1056  | 
if not isinstance(value, StringTypes):  | 
|
1057  | 
raise VdtTypeError(value)  | 
|
1058  | 
if not value in options:  | 
|
1059  | 
raise VdtValueError(value)  | 
|
1060  | 
return value  | 
|
1061  | 
||
1062  | 
if __name__ == '__main__':  | 
|
1063  | 
    # run the code tests in doctest format
 | 
|
1064  | 
import doctest  | 
|
1065  | 
m = sys.modules.get('__main__')  | 
|
1066  | 
globs = m.__dict__.copy()  | 
|
1067  | 
globs.update({  | 
|
1068  | 
'INTP_VER': INTP_VER,  | 
|
1069  | 
'vtor': Validator(),  | 
|
1070  | 
    })
 | 
|
1071  | 
doctest.testmod(m, globs=globs)  | 
|
1072  | 
||
1073  | 
"""
 | 
|
1074  | 
    TODO
 | 
|
1075  | 
    ====
 | 
|
1076  | 
    
 | 
|
1077  | 
    Consider which parts of the regex stuff to put back in
 | 
|
1078  | 
    
 | 
|
1079  | 
    Can we implement a timestamp datatype ? (check DateUtil module)
 | 
|
1080  | 
    
 | 
|
1081  | 
    ISSUES
 | 
|
1082  | 
    ======
 | 
|
1083  | 
    
 | 
|
1084  | 
    Lists passed as function arguments need additional quotes. Ugly, could do
 | 
|
1085  | 
    with fixing this.
 | 
|
1086  | 
    
 | 
|
1087  | 
    If we could pull tuples out of arguments, it would be easier
 | 
|
1088  | 
    to specify arguments for 'mixed_lists'.
 | 
|
1089  | 
    
 | 
|
1090  | 
    CHANGELOG
 | 
|
1091  | 
    =========
 | 
|
1092  | 
    
 | 
|
1093  | 
    2005/08/25
 | 
|
1094  | 
    ----------
 | 
|
1095  | 
    
 | 
|
1096  | 
    Most errors now prefixed ``Vdt``
 | 
|
1097  | 
    
 | 
|
1098  | 
    ``VdtParamError`` no longer derives from ``VdtError``
 | 
|
1099  | 
    
 | 
|
1100  | 
    Finalised as version 0.2.0
 | 
|
1101  | 
    
 | 
|
1102  | 
    2005/08/21
 | 
|
1103  | 
    ----------
 | 
|
1104  | 
    
 | 
|
1105  | 
    By Nicola Larosa
 | 
|
1106  | 
    
 | 
|
1107  | 
    Removed the "length" argument for lists and strings, and related tests
 | 
|
1108  | 
    
 | 
|
1109  | 
    2005/08/16
 | 
|
1110  | 
    ----------
 | 
|
1111  | 
    
 | 
|
1112  | 
    By Nicola Larosa
 | 
|
1113  | 
    
 | 
|
1114  | 
    Deleted the "none" and "multiple" types and checks
 | 
|
1115  | 
    
 | 
|
1116  | 
    Added the None value for all types in Validation.check
 | 
|
1117  | 
    
 | 
|
1118  | 
    2005/08/14
 | 
|
1119  | 
    ----------
 | 
|
1120  | 
    
 | 
|
1121  | 
    By Michael Foord
 | 
|
1122  | 
    
 | 
|
1123  | 
    Removed timestamp.
 | 
|
1124  | 
    
 | 
|
1125  | 
    By Nicola Larosa
 | 
|
1126  | 
    
 | 
|
1127  | 
    Fixed bug in Validator.check: when a value that has a default is also
 | 
|
1128  | 
    specified in the config file, the default must be deleted from fun_kwargs
 | 
|
1129  | 
    anyway, otherwise the check function will get a spurious "default" keyword
 | 
|
1130  | 
    argument
 | 
|
1131  | 
    
 | 
|
1132  | 
    Added "ip_addr_list" check
 | 
|
1133  | 
    
 | 
|
1134  | 
    2005/08/13
 | 
|
1135  | 
    ----------
 | 
|
1136  | 
    
 | 
|
1137  | 
    By Nicola Larosa
 | 
|
1138  | 
    
 | 
|
1139  | 
    Updated comments at top
 | 
|
1140  | 
    
 | 
|
1141  | 
    2005/08/11
 | 
|
1142  | 
    ----------
 | 
|
1143  | 
    
 | 
|
1144  | 
    By Nicola Larosa
 | 
|
1145  | 
    
 | 
|
1146  | 
    Added test for interpreter version: raises RuntimeError if earlier than
 | 
|
1147  | 
    2.2
 | 
|
1148  | 
    
 | 
|
1149  | 
    Fixed last is_mixed_list test to work on Python 2.2 too
 | 
|
1150  | 
    
 | 
|
1151  | 
    2005/08/10
 | 
|
1152  | 
    ----------
 | 
|
1153  | 
    
 | 
|
1154  | 
    By Nicola Larosa
 | 
|
1155  | 
    
 | 
|
1156  | 
    Restored Python2.2 compatibility by avoiding usage of dict.pop
 | 
|
1157  | 
    
 | 
|
1158  | 
    2005/08/07
 | 
|
1159  | 
    ----------
 | 
|
1160  | 
    
 | 
|
1161  | 
    By Nicola Larosa
 | 
|
1162  | 
    
 | 
|
1163  | 
    Adjusted doctests for Python 2.2.3 compatibility, one test still fails
 | 
|
1164  | 
    for trivial reasons (string output delimiters)
 | 
|
1165  | 
    
 | 
|
1166  | 
    2005/08/05
 | 
|
1167  | 
    ----------
 | 
|
1168  | 
    
 | 
|
1169  | 
    By Michael Foord
 | 
|
1170  | 
    
 | 
|
1171  | 
    Added __version__, __all__, and __docformat__
 | 
|
1172  | 
    
 | 
|
1173  | 
    Replaced ``basestring`` with ``types.StringTypes``
 | 
|
1174  | 
    
 | 
|
1175  | 
    2005/07/28
 | 
|
1176  | 
    ----------
 | 
|
1177  | 
    
 | 
|
1178  | 
    By Nicola Larosa
 | 
|
1179  | 
    
 | 
|
1180  | 
    Reformatted final docstring in ReST format, indented it for easier folding
 | 
|
1181  | 
    
 | 
|
1182  | 
    2005/07/20
 | 
|
1183  | 
    ----------
 | 
|
1184  | 
    
 | 
|
1185  | 
    By Nicola Larosa
 | 
|
1186  | 
    
 | 
|
1187  | 
    Added an 'ip_addr' IPv4 address value check, with tests
 | 
|
1188  | 
    
 | 
|
1189  | 
    Updated the tests for mixed_list to include IP addresses
 | 
|
1190  | 
    
 | 
|
1191  | 
    Changed all references to value "tests" into value "checks", including
 | 
|
1192  | 
    the main Validator method, and all code tests
 | 
|
1193  | 
    
 | 
|
1194  | 
    2005/07/19
 | 
|
1195  | 
    ----------
 | 
|
1196  | 
    
 | 
|
1197  | 
    By Nicola Larosa
 | 
|
1198  | 
    
 | 
|
1199  | 
    Added even more code tests
 | 
|
1200  | 
    
 | 
|
1201  | 
    Refined the mixed_list check
 | 
|
1202  | 
    
 | 
|
1203  | 
    2005/07/18
 | 
|
1204  | 
    ----------
 | 
|
1205  | 
    
 | 
|
1206  | 
    By Nicola Larosa
 | 
|
1207  | 
    
 | 
|
1208  | 
    Introduced more VdtValueError subclasses
 | 
|
1209  | 
    
 | 
|
1210  | 
    Collapsed the ``_function_test`` and ``_function_parse`` methods into the
 | 
|
1211  | 
    ``check`` one
 | 
|
1212  | 
    
 | 
|
1213  | 
    Refined the value checks, using the new VdtValueError subclasses
 | 
|
1214  | 
    
 | 
|
1215  | 
    Changed "is_string" to use "is_list"
 | 
|
1216  | 
    
 | 
|
1217  | 
    Added many more code tests
 | 
|
1218  | 
    
 | 
|
1219  | 
    Changed the "bool" value type to "boolean"
 | 
|
1220  | 
    
 | 
|
1221  | 
    Some more code cleanup
 | 
|
1222  | 
    
 | 
|
1223  | 
    2005/07/17
 | 
|
1224  | 
    ----------
 | 
|
1225  | 
    
 | 
|
1226  | 
    By Nicola Larosa
 | 
|
1227  | 
    
 | 
|
1228  | 
    Code tests converted to doctest format and placed in the respective
 | 
|
1229  | 
    docstrings, so they are automatically checked, and easier to update
 | 
|
1230  | 
    
 | 
|
1231  | 
    Changed local vars "min" and "max" to "min_len", "max_len", "min_val" and
 | 
|
1232  | 
    "max_val", to avoid shadowing the builtin functions (but left function
 | 
|
1233  | 
    parameters alone)
 | 
|
1234  | 
    
 | 
|
1235  | 
    Uniformed value check function names to is_* convention
 | 
|
1236  | 
    
 | 
|
1237  | 
    ``date`` type name changed to ``timestamp``
 | 
|
1238  | 
    
 | 
|
1239  | 
    Avoided some code duplication in list check functions
 | 
|
1240  | 
    
 | 
|
1241  | 
    Some more code cleanup
 | 
|
1242  | 
    
 | 
|
1243  | 
    2005/07/09
 | 
|
1244  | 
    ----------
 | 
|
1245  | 
    
 | 
|
1246  | 
    Recoded the standard functions
 | 
|
1247  | 
    
 | 
|
1248  | 
    2005/07/08
 | 
|
1249  | 
    ----------
 | 
|
1250  | 
    
 | 
|
1251  | 
    Improved paramfinder regex
 | 
|
1252  | 
    
 | 
|
1253  | 
    Ripped out all the regex stuff, checks, and the example functions
 | 
|
1254  | 
    (to be replaced !)
 | 
|
1255  | 
    
 | 
|
1256  | 
    2005/07/06
 | 
|
1257  | 
    ----------
 | 
|
1258  | 
    
 | 
|
1259  | 
    By Nicola Larosa
 | 
|
1260  | 
    
 | 
|
1261  | 
    Code cleanup
 | 
|
1262  | 
"""
 | 
|
1263  |