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 |