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
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.
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.
20
The Validator object is used to check that supplied values
21
conform to a specification.
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.
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
35
The standard functions work with the following basic data types :
43
plus lists of these datatypes
45
Adding additional checks is done through coding simple functions.
47
The full set of standard checks are :
49
* 'integer': matches integer values (including negative)
50
Takes optional 'min' and 'max' arguments : ::
53
integer(3, 9) # any value from 3 to 9
54
integer(min=0) # any positive value
57
* 'float': matches float values
58
Has the same parameters as the integer check.
60
* 'boolean': matches boolean values - ``True`` or ``False``
61
Acceptable string values for True are :
63
Acceptable string values for False are :
66
Any other value raises an error.
68
* 'ip_addr': matches an Internet Protocol address, v.4, represented
69
by a dotted-quad string, i.e. '1.2.3.4'.
71
* 'string': matches any string.
72
Takes optional keyword args 'min' and 'max'
73
to specify min and max lengths of the string.
75
* 'list': matches any list.
76
Takes optional keyword args 'min', and 'max' to specify min and
77
max sizes of the list.
79
* 'int_list': Matches a list of integers.
80
Takes the same arguments as list.
82
* 'float_list': Matches a list of floats.
83
Takes the same arguments as list.
85
* 'bool_list': Matches a list of boolean values.
86
Takes the same arguments as list.
88
* 'ip_addr_list': Matches a list of IP addresses.
89
Takes the same arguments as list.
91
* 'string_list': Matches a list of strings.
92
Takes the same arguments as list.
94
* 'mixed_list': Matches a list with different types in
95
specific positions. List size must match
96
the number of arguments.
98
Each position can be one of :
99
'integer', 'float', 'ip_addr', 'string', 'boolean'
101
So to specify a list with two strings followed
102
by two integers, you write the check as : ::
104
mixed_list('string', 'string', 'integer', 'integer')
106
* 'pass': This check matches everything ! It never fails
107
and the value is unchanged.
109
It is also the default if no check is specified.
111
* 'option': This check matches any from a list of options.
112
You specify this check with : ::
114
option('option 1', 'option 2', 'option 3')
117
__docformat__ = "restructuredtext en"
119
__version__ = '0.2.0'
121
__revision__ = '$Id: validate.py 123 2005-09-08 08:54:28Z fuzzyman $'
128
'VdtUnknownCheckError',
132
'VdtValueTooSmallError',
133
'VdtValueTooBigError',
134
'VdtValueTooShortError',
135
'VdtValueTooLongError',
155
INTP_VER = sys.version_info[:2]
156
if INTP_VER < (2, 2):
157
raise RuntimeError("Python v.2.2 or later needed")
160
StringTypes = (str, unicode)
162
# Python pre 2.2.1 doesn't have bool
167
"""Simple boolean equivalent function. """
173
def dottedQuadToNum(ip):
175
Convert decimal dotted quad string to long integer
177
>>> dottedQuadToNum('1 ')
179
>>> dottedQuadToNum(' 1.2')
181
>>> dottedQuadToNum(' 1.2.3 ')
183
>>> dottedQuadToNum('1.2.3.4')
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')
190
>>> dottedQuadToNum('255.255.255.256')
191
Traceback (most recent call last):
192
ValueError: Not a good dotted-quad IP: 255.255.255.256
195
# import here to avoid it when ip_addr values are not used
196
import socket, struct
199
return struct.unpack('!L',
200
socket.inet_aton(ip.strip()))[0]
202
# bug in inet_aton, corrected in Python 2.3
203
if ip.strip() == '255.255.255.255':
206
raise ValueError('Not a good dotted-quad IP: %s' % ip)
209
def numToDottedQuad(num):
211
Convert long int to dotted quad string
213
>>> numToDottedQuad(-1L)
214
Traceback (most recent call last):
215
ValueError: Not a good numeric IP: -1
216
>>> numToDottedQuad(1L)
218
>>> numToDottedQuad(16777218L)
220
>>> numToDottedQuad(16908291L)
222
>>> numToDottedQuad(16909060L)
224
>>> numToDottedQuad(4294967295L)
226
>>> numToDottedQuad(4294967296L)
227
Traceback (most recent call last):
228
ValueError: Not a good numeric IP: 4294967296
231
# import here to avoid it when ip_addr values are not used
232
import socket, struct
234
# no need to intercept here, 4294967295L is fine
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)
241
class ValidateError(Exception):
243
This error indicates that the check failed.
244
It can be the base class for more specific errors.
246
Any check function that fails ought to raise this error.
249
>>> raise ValidateError
250
Traceback (most recent call last):
254
class VdtMissingValue(ValidateError):
255
"""No value was supplied to a check that needed one."""
257
class VdtUnknownCheckError(ValidateError):
258
"""An unknown check function was requested"""
260
def __init__(self, value):
262
>>> raise VdtUnknownCheckError('yoda')
263
Traceback (most recent call last):
264
VdtUnknownCheckError: the check "yoda" is unknown.
266
ValidateError.__init__(
268
'the check "%s" is unknown.' % value)
270
class VdtParamError(SyntaxError):
271
"""An incorrect parameter was passed"""
273
def __init__(self, name, value):
275
>>> raise VdtParamError('yoda', 'jedi')
276
Traceback (most recent call last):
277
VdtParamError: passed an incorrect value "jedi" for parameter "yoda".
279
SyntaxError.__init__(
281
'passed an incorrect value "%s" for parameter "%s".' % (
284
class VdtTypeError(ValidateError):
285
"""The value supplied was of the wrong type"""
287
def __init__(self, value):
289
>>> raise VdtTypeError('jedi')
290
Traceback (most recent call last):
291
VdtTypeError: the value "jedi" is of the wrong type.
293
ValidateError.__init__(
295
'the value "%s" is of the wrong type.' % value)
297
class VdtValueError(ValidateError):
299
The value supplied was of the correct type, but was not an allowed value.
302
def __init__(self, value):
304
>>> raise VdtValueError('jedi')
305
Traceback (most recent call last):
306
VdtValueError: the value "jedi" is unacceptable.
308
ValidateError.__init__(
310
'the value "%s" is unacceptable.' % value)
312
class VdtValueTooSmallError(VdtValueError):
313
"""The value supplied was of the correct type, but was too small."""
315
def __init__(self, value):
317
>>> raise VdtValueTooSmallError('0')
318
Traceback (most recent call last):
319
VdtValueTooSmallError: the value "0" is too small.
321
ValidateError.__init__(
323
'the value "%s" is too small.' % value)
325
class VdtValueTooBigError(VdtValueError):
326
"""The value supplied was of the correct type, but was too big."""
328
def __init__(self, value):
330
>>> raise VdtValueTooBigError('1')
331
Traceback (most recent call last):
332
VdtValueTooBigError: the value "1" is too big.
334
ValidateError.__init__(
336
'the value "%s" is too big.' % value)
338
class VdtValueTooShortError(VdtValueError):
339
"""The value supplied was of the correct type, but was too short."""
341
def __init__(self, value):
343
>>> raise VdtValueTooShortError('jed')
344
Traceback (most recent call last):
345
VdtValueTooShortError: the value "jed" is too short.
347
ValidateError.__init__(
349
'the value "%s" is too short.' % (value,))
351
class VdtValueTooLongError(VdtValueError):
352
"""The value supplied was of the correct type, but was too long."""
354
def __init__(self, value):
356
>>> raise VdtValueTooLongError('jedie')
357
Traceback (most recent call last):
358
VdtValueTooLongError: the value "jedie" is too long.
360
ValidateError.__init__(
362
'the value "%s" is too long.' % (value,))
364
class Validator(object):
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.
369
This can also involve converting the value from a string into
370
the correct datatype.
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.
375
An example input string would be:
376
'int_range(param1, param2)'
378
You would then provide something like:
380
>>> def int_range_check(value, min, max):
381
... # turn min and max from strings to integers
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
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)
403
>>> fdict = {'int_range': int_range_check}
404
>>> vtr1 = Validator(fdict)
405
>>> vtr1.check('int_range(20, 40)', '30')
407
>>> vtr1.check('int_range(20, 40)', '60')
408
Traceback (most recent call last):
409
VdtValueTooBigError: the value "60" is too big.
411
New functions can be added with : ::
413
>>> vtr2 = Validator()
414
>>> vtr2.functions['int_range'] = int_range_check
416
Or by passing in a dictionary of functions when Validator
419
Your functions *can* use keyword arguments,
420
but the first argument should always be 'value'.
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 : ::
426
keyword = function_name
427
keyword = function_name()
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
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'(.+?)\((.*)\)')
443
def __init__(self, functions=None):
445
>>> vtri = Validator()
449
'integer': is_integer,
452
'ip_addr': is_ip_addr,
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,
464
if functions is not None:
465
self.functions.update(functions)
466
# tekNico: for use by ConfigObj
467
self.baseErrorClass = ValidateError
469
def check(self, check, value, missing=False):
471
Usage: check(check, value)
474
check: string representing check to apply (including arguments)
475
value: object to be checked
476
Returns value, converted to correct type if necessary
478
If the check fails, raises a ``ValidateError`` subclass.
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.
487
fun_match = self._func_re.match(check)
489
fun_name = fun_match.group(1)
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)
496
keymatch = self._key_arg.match(arg)
498
val = keymatch.group(2)
499
if (val[0] in ("'", '"')) and (val[0] == val[-1]):
501
fun_kwargs[keymatch.group(1)] = val
504
if (arg[0] in ("'", '"')) and (arg[0] == arg[-1]):
508
# allows for function names without (args)
509
(fun_name, fun_args, fun_kwargs) = (check, (), {})
513
value = fun_kwargs['default']
515
raise VdtMissingValue
520
# tekNico: default must be deleted if the value is specified too,
521
# otherwise the check function will get a spurious "default" keyword arg
523
del fun_kwargs['default']
527
return self.functions[fun_name](value, *fun_args, **fun_kwargs)
529
raise VdtUnknownCheckError(fun_name)
531
def _pass(self, value):
533
Dummy check that always passes
535
>>> vtor.check('', 0)
537
>>> vtor.check('', '0')
543
def _is_num_param(names, values, to_float=False):
545
Return numbers from inputs or raise VdtParamError.
547
Lets ``None`` pass through.
548
Pass in keyword argument ``to_float=True`` to
549
use float for the conversion rather than int.
551
>>> _is_num_param(('', ''), (0, 1.0))
553
>>> _is_num_param(('', ''), (0, 1.0), to_float=True)
555
>>> _is_num_param(('a'), ('a'))
556
Traceback (most recent call last):
557
VdtParamError: passed an incorrect value "a" for parameter "a".
559
fun = to_float and float or int
561
for (name, val) in zip(names, values):
563
out_params.append(val)
564
elif isinstance(val, (int, long, float, StringTypes)):
566
out_params.append(fun(val))
567
except ValueError, e:
568
raise VdtParamError(name, val)
570
raise VdtParamError(name, val)
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.
579
def is_integer(value, min=None, max=None):
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
585
If the value is a string, then the conversion is done - if possible.
586
Otherwise a VdtError is raised.
588
>>> vtor.check('integer', '-1')
590
>>> vtor.check('integer', '0')
592
>>> vtor.check('integer', 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')
602
>>> vtor.check('integer(max=20)', '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)
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 ?
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)
635
def is_float(value, min=None, max=None):
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.
640
If the value is a string, then the conversion is done - if possible.
641
Otherwise a VdtError is raised.
643
This can accept negative values.
645
>>> vtor.check('float', '2')
648
From now on we multiply the value to avoid comparing decimals
650
>>> vtor.check('float', '-6.8') * 10
652
>>> vtor.check('float', '12.2') * 10
654
>>> vtor.check('float', 8.4) * 10
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
661
>>> vtor.check('float(max=20.2)', '15.1') * 10
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.
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 ?
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)
687
True: True, 'on': True, '1': True, 'true': True, 'yes': True,
688
False: False, 'off': False, '0': False, 'false': False, 'no': False,
693
Check if the value represents a boolean.
695
>>> vtor.check('boolean', 0)
697
>>> vtor.check('boolean', False)
699
>>> vtor.check('boolean', '0')
701
>>> vtor.check('boolean', 'off')
703
>>> vtor.check('boolean', 'false')
705
>>> vtor.check('boolean', 'no')
707
>>> vtor.check('boolean', 'nO')
709
>>> vtor.check('boolean', 'NO')
711
>>> vtor.check('boolean', 1)
713
>>> vtor.check('boolean', True)
715
>>> vtor.check('boolean', '1')
717
>>> vtor.check('boolean', 'on')
719
>>> vtor.check('boolean', 'true')
721
>>> vtor.check('boolean', 'yes')
723
>>> vtor.check('boolean', 'Yes')
725
>>> vtor.check('boolean', 'YES')
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.
735
if isinstance(value, StringTypes):
737
return bool_dict[value.lower()]
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
748
raise VdtTypeError(value)
751
def is_ip_addr(value):
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'.
756
>>> vtor.check('ip_addr', '1 ')
758
>>> vtor.check('ip_addr', ' 1.2')
760
>>> vtor.check('ip_addr', ' 1.2.3 ')
762
>>> vtor.check('ip_addr', '1.2.3.4')
764
>>> vtor.check('ip_addr', '0.0.0.0')
766
>>> vtor.check('ip_addr', '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.
781
if not isinstance(value, StringTypes):
782
raise VdtTypeError(value)
783
value = value.strip()
785
dottedQuadToNum(value)
787
raise VdtValueError(value)
790
def is_list(value, min=None, max=None):
792
Check that the value is a list of values.
794
You can optionally specify the minimum and maximum number of members.
796
It does no check on list members.
798
>>> vtor.check('list', ())
800
>>> vtor.check('list', [])
802
>>> vtor.check('list', (1, 2))
804
>>> vtor.check('list', [1, 2])
806
>>> vtor.check('list', '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))
816
>>> vtor.check('list', 0)
817
Traceback (most recent call last):
818
VdtTypeError: the value "0" is of the wrong type.
820
(min_len, max_len) = _is_num_param(('min', 'max'), (min, max))
822
num_members = len(value)
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)
831
def is_string(value, min=None, max=None):
833
Check that the supplied value is a string.
835
You can optionally specify the minimum and maximum number of members.
837
>>> vtor.check('string', '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')
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')
849
>>> vtor.check('string(min=2, max=3)', '1234')
850
Traceback (most recent call last):
851
VdtValueTooLongError: the value "1234" is too long.
853
if not isinstance(value, StringTypes):
854
raise VdtTypeError(value)
855
return is_list(value, min, max)
857
def is_int_list(value, min=None, max=None):
859
Check that the value is a list of integers.
861
You can optionally specify the minimum and maximum number of members.
863
Each list member is checked that it is an integer.
865
>>> vtor.check('int_list', ())
867
>>> vtor.check('int_list', [])
869
>>> vtor.check('int_list', (1, 2))
871
>>> vtor.check('int_list', [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.
877
return [is_integer(mem) for mem in is_list(value, min, max)]
879
def is_bool_list(value, min=None, max=None):
881
Check that the value is a list of booleans.
883
You can optionally specify the minimum and maximum number of members.
885
Each list member is checked that it is a boolean.
887
>>> vtor.check('bool_list', ())
889
>>> vtor.check('bool_list', [])
891
>>> check_res = vtor.check('bool_list', (True, False))
892
>>> check_res == [True, False]
894
>>> check_res = vtor.check('bool_list', [True, False])
895
>>> check_res == [True, False]
897
>>> vtor.check('bool_list', [True, 'a'])
898
Traceback (most recent call last):
899
VdtTypeError: the value "a" is of the wrong type.
901
return [is_bool(mem) for mem in is_list(value, min, max)]
903
def is_float_list(value, min=None, max=None):
905
Check that the value is a list of floats.
907
You can optionally specify the minimum and maximum number of members.
909
Each list member is checked that it is a float.
911
>>> vtor.check('float_list', ())
913
>>> vtor.check('float_list', [])
915
>>> vtor.check('float_list', (1, 2.0))
917
>>> vtor.check('float_list', [1, 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.
923
return [is_float(mem) for mem in is_list(value, min, max)]
925
def is_string_list(value, min=None, max=None):
927
Check that the value is a list of strings.
929
You can optionally specify the minimum and maximum number of members.
931
Each list member is checked that it is a string.
933
>>> vtor.check('string_list', ())
935
>>> vtor.check('string_list', [])
937
>>> vtor.check('string_list', ('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.
943
return [is_string(mem) for mem in is_list(value, min, max)]
945
def is_ip_addr_list(value, min=None, max=None):
947
Check that the value is a list of IP addresses.
949
You can optionally specify the minimum and maximum number of members.
951
Each list member is checked that it is an IP address.
953
>>> vtor.check('ip_addr_list', ())
955
>>> vtor.check('ip_addr_list', [])
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.
963
return [is_ip_addr(mem) for mem in is_list(value, min, max)]
966
'integer': is_integer,
968
'ip_addr': is_ip_addr,
973
def is_mixed_list(value, *args):
975
Check that the value is a list.
976
Allow specifying the type of each member.
977
Work on lists of specific lengths.
979
You specify each member as a positional argument specifying type
981
Each type should be one of the following strings :
982
'integer', 'float', 'ip_addr', 'string', 'boolean'
984
So you can specify a list of two strings, followed by
987
mixed_list('string', 'string', 'integer', 'integer')
989
The length of the list must match the number of positional
990
arguments you supply.
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]
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]
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.
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 .
1016
... 'passed an incorrect value "',
1018
... '" for parameter "mixed_list".',
1020
>>> if INTP_VER == (2, 2):
1021
... res_str = "".join(res_seq)
1023
... res_str = "'".join(res_seq)
1025
... vtor.check('mixed_list("yoda")', ('a'))
1026
... except VdtParamError, err:
1027
... str(err) == res_str
1033
raise VdtTypeError(value)
1034
if length < len(args):
1035
raise VdtValueTooShortError(value)
1036
elif length > len(args):
1037
raise VdtValueTooLongError(value)
1039
return [fun_dict[arg](val) for arg, val in zip(args, value)]
1041
raise VdtParamError('mixed_list', e)
1043
def is_option(value, *options):
1045
This check matches the value to any of a set of options.
1047
>>> vtor.check('option("yoda", "jedi")', '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.
1056
if not isinstance(value, StringTypes):
1057
raise VdtTypeError(value)
1058
if not value in options:
1059
raise VdtValueError(value)
1062
if __name__ == '__main__':
1063
# run the code tests in doctest format
1065
m = sys.modules.get('__main__')
1066
globs = m.__dict__.copy()
1068
'INTP_VER': INTP_VER,
1069
'vtor': Validator(),
1071
doctest.testmod(m, globs=globs)
1077
Consider which parts of the regex stuff to put back in
1079
Can we implement a timestamp datatype ? (check DateUtil module)
1084
Lists passed as function arguments need additional quotes. Ugly, could do
1087
If we could pull tuples out of arguments, it would be easier
1088
to specify arguments for 'mixed_lists'.
1096
Most errors now prefixed ``Vdt``
1098
``VdtParamError`` no longer derives from ``VdtError``
1100
Finalised as version 0.2.0
1107
Removed the "length" argument for lists and strings, and related tests
1114
Deleted the "none" and "multiple" types and checks
1116
Added the None value for all types in Validation.check
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
1132
Added "ip_addr_list" check
1139
Updated comments at top
1146
Added test for interpreter version: raises RuntimeError if earlier than
1149
Fixed last is_mixed_list test to work on Python 2.2 too
1156
Restored Python2.2 compatibility by avoiding usage of dict.pop
1163
Adjusted doctests for Python 2.2.3 compatibility, one test still fails
1164
for trivial reasons (string output delimiters)
1171
Added __version__, __all__, and __docformat__
1173
Replaced ``basestring`` with ``types.StringTypes``
1180
Reformatted final docstring in ReST format, indented it for easier folding
1187
Added an 'ip_addr' IPv4 address value check, with tests
1189
Updated the tests for mixed_list to include IP addresses
1191
Changed all references to value "tests" into value "checks", including
1192
the main Validator method, and all code tests
1199
Added even more code tests
1201
Refined the mixed_list check
1208
Introduced more VdtValueError subclasses
1210
Collapsed the ``_function_test`` and ``_function_parse`` methods into the
1213
Refined the value checks, using the new VdtValueError subclasses
1215
Changed "is_string" to use "is_list"
1217
Added many more code tests
1219
Changed the "bool" value type to "boolean"
1221
Some more code cleanup
1228
Code tests converted to doctest format and placed in the respective
1229
docstrings, so they are automatically checked, and easier to update
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
1235
Uniformed value check function names to is_* convention
1237
``date`` type name changed to ``timestamp``
1239
Avoided some code duplication in list check functions
1241
Some more code cleanup
1246
Recoded the standard functions
1251
Improved paramfinder regex
1253
Ripped out all the regex stuff, checks, and the example functions