Coverage for src/robotide/preferences/configobj/src/configobj/validate.py: 55%
271 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-06 10:40 +0100
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-06 10:40 +0100
1# validate.py
2# A Validator object
3# Copyright (C) 2005-2014:
4# (name) : (email)
5# Michael Foord: fuzzyman AT voidspace DOT org DOT uk
6# Mark Andrews: mark AT la-la DOT com
7# Nicola Larosa: nico AT tekNico DOT net
8# Rob Dennis: rdennis AT gmail DOT com
9# Eli Courtwright: eli AT courtwright DOT org
11# This software is licensed under the terms of the BSD license.
12# http://opensource.org/licenses/BSD-3-Clause
14# ConfigObj 5 - main repository for documentation and issue tracking:
15# https://github.com/DiffSK/configobj
17"""
18 The Validator object is used to check that supplied values
19 conform to a specification.
21 The value can be supplied as a string - e.g. from a config file.
22 In this case the check will also *convert* the value to
23 the required type. This allows you to add validation
24 as a transparent layer to access data stored as strings.
25 The validation checks that the data is correct *and*
26 converts it to the expected type.
28 Some standard checks are provided for basic data types.
29 Additional checks are easy to write. They can be
30 provided when the ``Validator`` is instantiated or
31 added afterwards.
33 The standard functions work with the following basic data types :
35 * integers
36 * floats
37 * booleans
38 * strings
39 * ip_addr
41 plus lists of these datatypes
43 Adding additional checks is done through coding simple functions.
45 The full set of standard checks are :
47 * 'integer': matches integer values (including negative)
48 Takes optional 'min' and 'max' arguments : ::
50 integer()
51 integer(3, 9) # any value from 3 to 9
52 integer(min=0) # any positive value
53 integer(max=9)
55 * 'float': matches float values
56 Has the same parameters as the integer check.
58 * 'boolean': matches boolean values - ``True`` or ``False``
59 Acceptable string values for True are :
60 true, on, yes, 1
61 Acceptable string values for False are :
62 false, off, no, 0
64 Any other value raises an error.
66 * 'ip_addr': matches an Internet Protocol address, v.4, represented
67 by a dotted-quad string, i.e. '1.2.3.4'.
69 * 'string': matches any string.
70 Takes optional keyword args 'min' and 'max'
71 to specify min and max lengths of the string.
73 * 'list': matches any list.
74 Takes optional keyword args 'min', and 'max' to specify min and
75 max sizes of the list. (Always returns a list.)
77 * 'tuple': matches any tuple.
78 Takes optional keyword args 'min', and 'max' to specify min and
79 max sizes of the tuple. (Always returns a tuple.)
81 * 'int_list': Matches a list of integers.
82 Takes the same arguments as list.
84 * 'float_list': Matches a list of floats.
85 Takes the same arguments as list.
87 * 'bool_list': Matches a list of boolean values.
88 Takes the same arguments as list.
90 * 'ip_addr_list': Matches a list of IP addresses.
91 Takes the same arguments as list.
93 * 'string_list': Matches a list of strings.
94 Takes the same arguments as list.
96 * 'mixed_list': Matches a list with different types in
97 specific positions. List size must match
98 the number of arguments.
100 Each position can be one of :
101 'integer', 'float', 'ip_addr', 'string', 'boolean'
103 So to specify a list with two strings followed
104 by two integers, you write the check as : ::
106 mixed_list('string', 'string', 'integer', 'integer')
108 * 'pass': This check matches everything ! It never fails
109 and the value is unchanged.
111 It is also the default if no check is specified.
113 * 'option': This check matches any from a list of options.
114 You specify this check with : ::
116 option('option 1', 'option 2', 'option 3')
118 You can supply a default value (returned if no value is supplied)
119 using the default keyword argument.
121 You specify a list argument for default using a list constructor syntax in
122 the check : ::
124 checkname(arg1, arg2, default=list('val 1', 'val 2', 'val 3'))
126 A badly formatted set of arguments will raise a ``VdtParamError``.
127"""
129__version__ = '1.0.1'
132__all__ = (
133 '__version__',
134 'dottedQuadToNum',
135 'numToDottedQuad',
136 'ValidateError',
137 'VdtUnknownCheckError',
138 'VdtParamError',
139 'VdtTypeError',
140 'VdtValueError',
141 'VdtValueTooSmallError',
142 'VdtValueTooBigError',
143 'VdtValueTooShortError',
144 'VdtValueTooLongError',
145 'VdtMissingValue',
146 'Validator',
147 'is_integer',
148 'is_float',
149 'is_boolean',
150 'is_list',
151 'is_tuple',
152 'is_ip_addr',
153 'is_string',
154 'is_int_list',
155 'is_bool_list',
156 'is_float_list',
157 'is_string_list',
158 'is_ip_addr_list',
159 'is_mixed_list',
160 'is_option',
161)
164import re
165import sys
166from pprint import pprint
169_list_arg = re.compile(r'''
170 (?:
171 ([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*list\(
172 (
173 (?:
174 \s*
175 (?:
176 (?:".*?")| # double quotes
177 (?:'.*?')| # single quotes
178 (?:[^'",\s\)][^,\)]*?) # unquoted
179 )
180 \s*,\s*
181 )*
182 (?:
183 (?:".*?")| # double quotes
184 (?:'.*?')| # single quotes
185 (?:[^'",\s\)][^,\)]*?) # unquoted
186 )? # last one
187 )
188 \)
189 )
190''', re.VERBOSE | re.DOTALL) # two groups
192_list_members = re.compile(r'''
193 (
194 (?:".*?")| # double quotes
195 (?:'.*?')| # single quotes
196 (?:[^'",\s=][^,=]*?) # unquoted
197 )
198 (?:
199 (?:\s*,\s*)|(?:\s*$) # comma
200 )
201''', re.VERBOSE | re.DOTALL) # one group
203_paramstring = r'''
204 (?:
205 (
206 (?:
207 [a-zA-Z_][a-zA-Z0-9_]*\s*=\s*list\(
208 (?:
209 \s*
210 (?:
211 (?:".*?")| # double quotes
212 (?:'.*?')| # single quotes
213 (?:[^'",\s\)][^,\)]*?) # unquoted
214 )
215 \s*,\s*
216 )*
217 (?:
218 (?:".*?")| # double quotes
219 (?:'.*?')| # single quotes
220 (?:[^'",\s\)][^,\)]*?) # unquoted
221 )? # last one
222 \)
223 )|
224 (?:
225 (?:".*?")| # double quotes
226 (?:'.*?')| # single quotes
227 (?:[^'",\s=][^,=]*?)| # unquoted
228 (?: # keyword argument
229 [a-zA-Z_][a-zA-Z0-9_]*\s*=\s*
230 (?:
231 (?:".*?")| # double quotes
232 (?:'.*?')| # single quotes
233 (?:[^'",\s=][^,=]*?) # unquoted
234 )
235 )
236 )
237 )
238 (?:
239 (?:\s*,\s*)|(?:\s*$) # comma
240 )
241 )
242 '''
244_matchstring = '^%s*' % _paramstring
247def dottedQuadToNum(ip):
248 """
249 Convert decimal dotted quad string to long integer
251 >>> int(dottedQuadToNum('1 '))
252 1
253 >>> int(dottedQuadToNum(' 1.2'))
254 16777218
255 >>> int(dottedQuadToNum(' 1.2.3 '))
256 16908291
257 >>> int(dottedQuadToNum('1.2.3.4'))
258 16909060
259 >>> dottedQuadToNum('255.255.255.255')
260 4294967295
261 >>> dottedQuadToNum('255.255.255.256')
262 Traceback (most recent call last):
263 ValueError: Not a good dotted-quad IP: 255.255.255.256
264 """
266 # import here to avoid it when ip_addr values are not used
267 import socket, struct
269 try:
270 return struct.unpack('!L',
271 socket.inet_aton(ip.strip()))[0]
272 except socket.error:
273 raise ValueError('Not a good dotted-quad IP: %s' % ip)
274 return
277def numToDottedQuad(num):
278 """
279 Convert int or long int to dotted quad string
281 >>> numToDottedQuad(int(-1))
282 Traceback (most recent call last):
283 ValueError: Not a good numeric IP: -1
284 >>> numToDottedQuad(int(1))
285 '0.0.0.1'
286 >>> numToDottedQuad(int(16777218))
287 '1.0.0.2'
288 >>> numToDottedQuad(int(16908291))
289 '1.2.0.3'
290 >>> numToDottedQuad(int(16909060))
291 '1.2.3.4'
292 >>> numToDottedQuad(int(4294967295))
293 '255.255.255.255'
294 >>> numToDottedQuad(int(4294967296))
295 Traceback (most recent call last):
296 ValueError: Not a good numeric IP: 4294967296
297 >>> numToDottedQuad(-1)
298 Traceback (most recent call last):
299 ValueError: Not a good numeric IP: -1
300 >>> numToDottedQuad(1)
301 '0.0.0.1'
302 >>> numToDottedQuad(16777218)
303 '1.0.0.2'
304 >>> numToDottedQuad(16908291)
305 '1.2.0.3'
306 >>> numToDottedQuad(16909060)
307 '1.2.3.4'
308 >>> numToDottedQuad(4294967295)
309 '255.255.255.255'
310 >>> numToDottedQuad(4294967296)
311 Traceback (most recent call last):
312 ValueError: Not a good numeric IP: 4294967296
314 """
316 # import here to avoid it when ip_addr values are not used
317 import socket, struct
319 # no need to intercept here, 4294967295L is fine
320 if num > int(4294967295) or num < 0:
321 raise ValueError('Not a good numeric IP: %s' % num)
322 try:
323 return socket.inet_ntoa(
324 struct.pack('!L', int(num)))
325 except (socket.error, struct.error, OverflowError):
326 raise ValueError('Not a good numeric IP: %s' % num)
329class ValidateError(Exception):
330 """
331 This error indicates that the check failed.
332 It can be the base class for more specific errors.
334 Any check function that fails ought to raise this error.
335 (or a subclass)
337 >>> raise ValidateError
338 Traceback (most recent call last):
339 ValidateError
340 """
343class VdtMissingValue(ValidateError):
344 """No value was supplied to a check that needed one."""
347class VdtUnknownCheckError(ValidateError):
348 """An unknown check function was requested"""
350 def __init__(self, value):
351 """
352 >>> raise VdtUnknownCheckError('yoda')
353 Traceback (most recent call last):
354 VdtUnknownCheckError: the check "yoda" is unknown.
355 """
356 ValidateError.__init__(self, 'the check "%s" is unknown.' % (value,))
359class VdtParamError(SyntaxError):
360 """An incorrect parameter was passed"""
362 def __init__(self, name, value):
363 """
364 >>> raise VdtParamError('yoda', 'jedi')
365 Traceback (most recent call last):
366 VdtParamError: passed an incorrect value "jedi" for parameter "yoda".
367 """
368 SyntaxError.__init__(self, 'passed an incorrect value "%s" for parameter "%s".' % (value, name))
371class VdtTypeError(ValidateError):
372 """The value supplied was of the wrong type"""
374 def __init__(self, value):
375 """
376 >>> raise VdtTypeError('jedi')
377 Traceback (most recent call last):
378 VdtTypeError: the value "jedi" is of the wrong type.
379 """
380 ValidateError.__init__(self, 'the value "%s" is of the wrong type.' % (value,))
383class VdtValueError(ValidateError):
384 """The value supplied was of the correct type, but was not an allowed value."""
386 def __init__(self, value):
387 """
388 >>> raise VdtValueError('jedi')
389 Traceback (most recent call last):
390 VdtValueError: the value "jedi" is unacceptable.
391 """
392 ValidateError.__init__(self, 'the value "%s" is unacceptable.' % (value,))
395class VdtValueTooSmallError(VdtValueError):
396 """The value supplied was of the correct type, but was too small."""
398 def __init__(self, value):
399 """
400 >>> raise VdtValueTooSmallError('0')
401 Traceback (most recent call last):
402 VdtValueTooSmallError: the value "0" is too small.
403 """
404 ValidateError.__init__(self, 'the value "%s" is too small.' % (value,)) 1d
407class VdtValueTooBigError(VdtValueError):
408 """The value supplied was of the correct type, but was too big."""
410 def __init__(self, value):
411 """
412 >>> raise VdtValueTooBigError('1')
413 Traceback (most recent call last):
414 VdtValueTooBigError: the value "1" is too big.
415 """
416 ValidateError.__init__(self, 'the value "%s" is too big.' % (value,))
419class VdtValueTooShortError(VdtValueError):
420 """The value supplied was of the correct type, but was too short."""
422 def __init__(self, value):
423 """
424 >>> raise VdtValueTooShortError('jed')
425 Traceback (most recent call last):
426 VdtValueTooShortError: the value "jed" is too short.
427 """
428 ValidateError.__init__(
429 self,
430 'the value "%s" is too short.' % (value,))
433class VdtValueTooLongError(VdtValueError):
434 """The value supplied was of the correct type, but was too long."""
436 def __init__(self, value):
437 """
438 >>> raise VdtValueTooLongError('jedie')
439 Traceback (most recent call last):
440 VdtValueTooLongError: the value "jedie" is too long.
441 """
442 ValidateError.__init__(self, 'the value "%s" is too long.' % (value,))
445class Validator(object):
446 """
447 Validator is an object that allows you to register a set of 'checks'.
448 These checks take input and test that it conforms to the check.
450 This can also involve converting the value from a string into
451 the correct datatype.
453 The ``check`` method takes an input string which configures which
454 check is to be used and applies that check to a supplied value.
456 An example input string would be:
457 'int_range(param1, param2)'
459 You would then provide something like:
461 >>> def int_range_check(value, min, max):
462 ... # turn min and max from strings to integers
463 ... min = int(min)
464 ... max = int(max)
465 ... # check that value is of the correct type.
466 ... # possible valid inputs are integers or strings
467 ... # that represent integers
468 ... if not isinstance(value, (int, str)):
469 ... raise VdtTypeError(value)
470 ... elif isinstance(value, str):
471 ... # if we are given a string
472 ... # attempt to convert to an integer
473 ... try:
474 ... value = int(value)
475 ... except ValueError:
476 ... raise VdtValueError(value)
477 ... # check the value is between our constraints
478 ... if not min <= value:
479 ... raise VdtValueTooSmallError(value)
480 ... if not value <= max:
481 ... raise VdtValueTooBigError(value)
482 ... return value
484 >>> fdict = {'int_range': int_range_check}
485 >>> vtr1 = Validator(fdict)
486 >>> vtr1.check('int_range(20, 40)', '30')
487 30
488 >>> vtr1.check('int_range(20, 40)', '60')
489 Traceback (most recent call last):
490 VdtValueTooBigError: the value "60" is too big.
492 New functions can be added with : ::
494 >>> vtr2 = Validator()
495 >>> vtr2.functions['int_range'] = int_range_check
497 Or by passing in a dictionary of functions when Validator
498 is instantiated.
500 Your functions *can* use keyword arguments,
501 but the first argument should always be 'value'.
503 If the function doesn't take additional arguments,
504 the parentheses are optional in the check.
505 It can be written with either of : ::
507 keyword = function_name
508 keyword = function_name()
510 The first program to utilise Validator() was Michael Foord's
511 ConfigObj, an alternative to ConfigParser which supports lists and
512 can validate a config file using a config schema.
513 For more details on using Validator with ConfigObj see:
514 https://configobj.readthedocs.org/en/latest/configobj.html
515 """
517 # this regex does the initial parsing of the checks
518 _func_re = re.compile(r'([^\(\)]+?)\((.*)\)', re.DOTALL)
520 # this regex takes apart keyword arguments
521 _key_arg = re.compile(r'^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.*)$', re.DOTALL)
524 # this regex finds keyword=list(....) type values
525 _list_arg = _list_arg
527 # this regex takes individual values out of lists - in one pass
528 _list_members = _list_members
530 # These regexes check a set of arguments for validity
531 # and then pull the members out
532 _paramfinder = re.compile(_paramstring, re.VERBOSE | re.DOTALL)
533 _matchfinder = re.compile(_matchstring, re.VERBOSE | re.DOTALL)
536 def __init__(self, functions=None):
537 """
538 >>> vtri = Validator()
539 """
540 self.functions = { 1cb
541 '': self._pass,
542 'integer': is_integer,
543 'float': is_float,
544 'boolean': is_boolean,
545 'ip_addr': is_ip_addr,
546 'string': is_string,
547 'list': is_list,
548 'tuple': is_tuple,
549 'int_list': is_int_list,
550 'float_list': is_float_list,
551 'bool_list': is_bool_list,
552 'ip_addr_list': is_ip_addr_list,
553 'string_list': is_string_list,
554 'mixed_list': is_mixed_list,
555 'pass': self._pass,
556 'option': is_option,
557 'force_list': force_list,
558 }
559 if functions is not None: 559 ↛ 560line 559 didn't jump to line 560 because the condition on line 559 was never true1cb
560 self.functions.update(functions)
561 # tekNico: for use by ConfigObj
562 self.baseErrorClass = ValidateError 1cb
563 self._cache = {} 1cb
566 def check(self, check, value, missing=False):
567 """
568 Usage: check(check, value)
570 Arguments:
571 check: string representing check to apply (including arguments)
572 value: object to be checked
573 Returns value, converted to correct type if necessary
575 If the check fails, raises a ``ValidateError`` subclass.
577 >>> vtor.check('yoda', '')
578 Traceback (most recent call last):
579 VdtUnknownCheckError: the check "yoda" is unknown.
580 >>> vtor.check('yoda()', '')
581 Traceback (most recent call last):
582 VdtUnknownCheckError: the check "yoda" is unknown.
584 >>> vtor.check('string(default="")', '', missing=True)
585 ''
586 """
587 fun_name, fun_args, fun_kwargs, default = self._parse_with_caching(check) 1bad
589 if missing: 1bad
590 if default is None: 590 ↛ 592line 590 didn't jump to line 592 because the condition on line 590 was never true1a
591 # no information needed here - to be handled by caller
592 raise VdtMissingValue()
593 value = self._handle_none(default) 1a
595 if value is None: 595 ↛ 596line 595 didn't jump to line 596 because the condition on line 595 was never true1bad
596 return None
598 return self._check_value(value, fun_name, fun_args, fun_kwargs) 1bad
601 def _handle_none(self, value):
602 if value == 'None': 602 ↛ 603line 602 didn't jump to line 603 because the condition on line 602 was never true1a
603 return None
604 elif value in ("'None'", '"None"'): 604 ↛ 606line 604 didn't jump to line 606 because the condition on line 604 was never true1a
605 # Special case a quoted None
606 value = self._unquote(value)
607 return value 1a
610 def _parse_with_caching(self, check):
611 if check in self._cache: 1bad
612 fun_name, fun_args, fun_kwargs, default = self._cache[check] 1bad
613 # We call list and dict below to work with *copies* of the data
614 # rather than the original (which are mutable of course)
615 fun_args = list(fun_args) 1bad
616 fun_kwargs = dict(fun_kwargs) 1bad
617 else:
618 fun_name, fun_args, fun_kwargs, default = self._parse_check(check) 1bad
619 fun_kwargs = dict([(str(key), value) for (key, value) in list(fun_kwargs.items())]) 1bad
620 self._cache[check] = fun_name, list(fun_args), dict(fun_kwargs), default 1bad
621 return fun_name, fun_args, fun_kwargs, default 1bad
624 def _check_value(self, value, fun_name, fun_args, fun_kwargs):
625 try: 1bad
626 fun = self.functions[fun_name] 1bad
627 except KeyError:
628 raise VdtUnknownCheckError(fun_name)
629 else:
630 return fun(value, *fun_args, **fun_kwargs) 1bad
633 def _parse_check(self, check):
634 fun_match = self._func_re.match(check) 1bad
635 if fun_match: 1bad
636 fun_name = fun_match.group(1) 1bad
637 arg_string = fun_match.group(2) 1bad
638 arg_match = self._matchfinder.match(arg_string) 1bad
639 if arg_match is None: 639 ↛ 641line 639 didn't jump to line 641 because the condition on line 639 was never true1bad
640 # Bad syntax
641 raise VdtParamError('Bad syntax in check "%s".' % check)
642 fun_args = [] 1bad
643 fun_kwargs = {} 1bad
644 # pull out args of group 2
645 for arg in self._paramfinder.findall(arg_string): 1bad
646 # args may need whitespace removing (before removing quotes)
647 arg = arg.strip() 1bad
648 listmatch = self._list_arg.match(arg) 1bad
649 if listmatch: 649 ↛ 650line 649 didn't jump to line 650 because the condition on line 649 was never true1bad
650 key, val = self._list_handle(listmatch)
651 fun_kwargs[key] = val
652 continue
653 keymatch = self._key_arg.match(arg) 1bad
654 if keymatch: 1bad
655 val = keymatch.group(2) 1a
656 if not val in ("'None'", '"None"'): 656 ↛ 659line 656 didn't jump to line 659 because the condition on line 656 was always true1a
657 # Special case a quoted None
658 val = self._unquote(val) 1a
659 fun_kwargs[keymatch.group(1)] = val 1a
660 continue 1a
662 fun_args.append(self._unquote(arg)) 1bd
663 else:
664 # allows for function names without (args)
665 return check, (), {}, None 1bd
667 # Default must be deleted if the value is specified too,
668 # otherwise the check function will get a spurious "default" keyword arg
669 default = fun_kwargs.pop('default', None) 1bad
670 return fun_name, fun_args, fun_kwargs, default 1bad
673 def _unquote(self, val):
674 """Unquote a value if necessary."""
675 if (len(val) >= 2) and (val[0] in ("'", '"')) and (val[0] == val[-1]): 675 ↛ 676line 675 didn't jump to line 676 because the condition on line 675 was never true1bad
676 val = val[1:-1]
677 return val 1bad
680 def _list_handle(self, listmatch):
681 """Take apart a ``keyword=list('val, 'val')`` type string."""
682 out = []
683 name = listmatch.group(1)
684 args = listmatch.group(2)
685 for arg in self._list_members.findall(args):
686 out.append(self._unquote(arg))
687 return name, out
690 def _pass(self, value):
691 """
692 Dummy check that always passes
694 >>> vtor.check('', 0)
695 0
696 >>> vtor.check('', '0')
697 '0'
698 """
699 return value
702 def get_default_value(self, check):
703 """
704 Given a check, return the default value for the check
705 (converted to the right type).
707 If the check doesn't specify a default value then a
708 ``KeyError`` will be raised.
709 """
710 fun_name, fun_args, fun_kwargs, default = self._parse_with_caching(check) 1bad
711 if default is None: 1bad
712 raise KeyError('Check "%s" has no default value.' % check) 1bd
713 value = self._handle_none(default) 1a
714 if value is None: 714 ↛ 715line 714 didn't jump to line 715 because the condition on line 714 was never true1a
715 return value
716 return self._check_value(value, fun_name, fun_args, fun_kwargs) 1a
719def _is_num_param(names, values, to_float=False):
720 """
721 Return numbers from inputs or raise VdtParamError.
723 Lets ``None`` pass through.
724 Pass in keyword argument ``to_float=True`` to
725 use float for the conversion rather than int.
727 >>> _is_num_param(('', ''), (0, 1.0))
728 [0, 1]
729 >>> _is_num_param(('', ''), (0, 1.0), to_float=True)
730 [0.0, 1.0]
731 >>> _is_num_param(('a'), ('a'))
732 Traceback (most recent call last):
733 VdtParamError: passed an incorrect value "a" for parameter "a".
734 """
735 fun = to_float and float or int 1bad
736 out_params = [] 1bad
737 for (name, val) in zip(names, values): 1bad
738 if val is None: 1bad
739 out_params.append(val) 1bad
740 elif isinstance(val, (int, float, str)): 740 ↛ 746line 740 didn't jump to line 746 because the condition on line 740 was always true1bd
741 try: 1bd
742 out_params.append(fun(val)) 1bd
743 except ValueError as e:
744 raise VdtParamError(name, val)
745 else:
746 raise VdtParamError(name, val)
747 return out_params 1bad
750# built in checks
751# you can override these by setting the appropriate name
752# in Validator.functions
753# note: if the params are specified wrongly in your input string,
754# you will also raise errors.
756def is_integer(value, min=None, max=None):
757 """
758 A check that tests that a given value is an integer (int)
759 and optionally, between bounds. A negative value is accepted, while
760 a float will fail.
762 If the value is a string, then the conversion is done - if possible.
763 Otherwise a VdtError is raised.
765 >>> vtor.check('integer', '-1')
766 -1
767 >>> vtor.check('integer', '0')
768 0
769 >>> vtor.check('integer', 9)
770 9
771 >>> vtor.check('integer', 'a')
772 Traceback (most recent call last):
773 VdtTypeError: the value "a" is of the wrong type.
774 >>> vtor.check('integer', '2.2')
775 Traceback (most recent call last):
776 VdtTypeError: the value "2.2" is of the wrong type.
777 >>> vtor.check('integer(10)', '20')
778 20
779 >>> vtor.check('integer(max=20)', '15')
780 15
781 >>> vtor.check('integer(10)', '9')
782 Traceback (most recent call last):
783 VdtValueTooSmallError: the value "9" is too small.
784 >>> vtor.check('integer(10)', 9)
785 Traceback (most recent call last):
786 VdtValueTooSmallError: the value "9" is too small.
787 >>> vtor.check('integer(max=20)', '35')
788 Traceback (most recent call last):
789 VdtValueTooBigError: the value "35" is too big.
790 >>> vtor.check('integer(max=20)', 35)
791 Traceback (most recent call last):
792 VdtValueTooBigError: the value "35" is too big.
793 >>> vtor.check('integer(0, 9)', False)
794 0
795 """
796 (min_val, max_val) = _is_num_param(('min', 'max'), (min, max)) 1bad
797 if not isinstance(value, (int, str)): 797 ↛ 798line 797 didn't jump to line 798 because the condition on line 797 was never true1bad
798 raise VdtTypeError(value)
799 if isinstance(value, str): 1bad
800 # if it's a string - does it represent an integer ?
801 try: 1bad
802 value = int(value) 1bad
803 except ValueError:
804 raise VdtTypeError(value)
805 if (min_val is not None) and (value < min_val): 805 ↛ 806line 805 didn't jump to line 806 because the condition on line 805 was never true1bad
806 raise VdtValueTooSmallError(value)
807 if (max_val is not None) and (value > max_val): 807 ↛ 808line 807 didn't jump to line 808 because the condition on line 807 was never true1bad
808 raise VdtValueTooBigError(value)
809 return value 1bad
812def is_float(value, min=None, max=None):
813 """
814 A check that tests that a given value is a float
815 (an integer will be accepted), and optionally - that it is between bounds.
817 If the value is a string, then the conversion is done - if possible.
818 Otherwise a VdtError is raised.
820 This can accept negative values.
822 >>> vtor.check('float', '2')
823 2.0
825 From now on we multiply the value to avoid comparing decimals
827 >>> vtor.check('float', '-6.8') * 10
828 -68.0
829 >>> vtor.check('float', '12.2') * 10
830 122.0
831 >>> vtor.check('float', 8.4) * 10
832 84.0
833 >>> vtor.check('float', 'a')
834 Traceback (most recent call last):
835 VdtTypeError: the value "a" is of the wrong type.
836 >>> vtor.check('float(10.1)', '10.2') * 10
837 102.0
838 >>> vtor.check('float(max=20.2)', '15.1') * 10
839 151.0
840 >>> vtor.check('float(10.0)', '9.0')
841 Traceback (most recent call last):
842 VdtValueTooSmallError: the value "9.0" is too small.
843 >>> vtor.check('float(max=20.0)', '35.0')
844 Traceback (most recent call last):
845 VdtValueTooBigError: the value "35.0" is too big.
846 """
847 (min_val, max_val) = _is_num_param( 1bad
848 ('min', 'max'), (min, max), to_float=True)
849 if not isinstance(value, (int, float, str)): 849 ↛ 850line 849 didn't jump to line 850 because the condition on line 849 was never true1bad
850 raise VdtTypeError(value)
851 if not isinstance(value, float): 851 ↛ 857line 851 didn't jump to line 857 because the condition on line 851 was always true1bad
852 # if it's a string - does it represent a float ?
853 try: 1bad
854 value = float(value) 1bad
855 except ValueError:
856 raise VdtTypeError(value)
857 if (min_val is not None) and (value < min_val): 1bad
858 raise VdtValueTooSmallError(value) 1d
859 if (max_val is not None) and (value > max_val): 859 ↛ 860line 859 didn't jump to line 860 because the condition on line 859 was never true1ba
860 raise VdtValueTooBigError(value)
861 return value 1ba
864bool_dict = {
865 True: True, 'on': True, '1': True, 'true': True, 'yes': True,
866 False: False, 'off': False, '0': False, 'false': False, 'no': False,
867}
870def is_boolean(value):
871 """
872 Check if the value represents a boolean.
874 >>> vtor.check('boolean', 0)
875 0
876 >>> vtor.check('boolean', False)
877 0
878 >>> vtor.check('boolean', '0')
879 0
880 >>> vtor.check('boolean', 'off')
881 0
882 >>> vtor.check('boolean', 'false')
883 0
884 >>> vtor.check('boolean', 'no')
885 0
886 >>> vtor.check('boolean', 'nO')
887 0
888 >>> vtor.check('boolean', 'NO')
889 0
890 >>> vtor.check('boolean', 1)
891 1
892 >>> vtor.check('boolean', True)
893 1
894 >>> vtor.check('boolean', '1')
895 1
896 >>> vtor.check('boolean', 'on')
897 1
898 >>> vtor.check('boolean', 'true')
899 1
900 >>> vtor.check('boolean', 'yes')
901 1
902 >>> vtor.check('boolean', 'Yes')
903 1
904 >>> vtor.check('boolean', 'YES')
905 1
906 >>> vtor.check('boolean', '')
907 Traceback (most recent call last):
908 VdtTypeError: the value "" is of the wrong type.
909 >>> vtor.check('boolean', 'up')
910 Traceback (most recent call last):
911 VdtTypeError: the value "up" is of the wrong type.
913 """
914 if isinstance(value, str): 914 ↛ 922line 914 didn't jump to line 922 because the condition on line 914 was always true1a
915 try: 1a
916 return bool_dict[value.lower()] 1a
917 except KeyError:
918 raise VdtTypeError(value)
919 # we do an equality test rather than an identity test
920 # this ensures Python 2.2 compatibilty
921 # and allows 0 and 1 to represent True and False
922 if value == False:
923 return False
924 elif value == True:
925 return True
926 else:
927 raise VdtTypeError(value)
930def is_ip_addr(value):
931 """
932 Check that the supplied value is an Internet Protocol address, v.4,
933 represented by a dotted-quad string, i.e. '1.2.3.4'.
935 >>> vtor.check('ip_addr', '1 ')
936 '1'
937 >>> vtor.check('ip_addr', ' 1.2')
938 '1.2'
939 >>> vtor.check('ip_addr', ' 1.2.3 ')
940 '1.2.3'
941 >>> vtor.check('ip_addr', '1.2.3.4')
942 '1.2.3.4'
943 >>> vtor.check('ip_addr', '0.0.0.0')
944 '0.0.0.0'
945 >>> vtor.check('ip_addr', '255.255.255.255')
946 '255.255.255.255'
947 >>> vtor.check('ip_addr', '255.255.255.256')
948 Traceback (most recent call last):
949 VdtValueError: the value "255.255.255.256" is unacceptable.
950 >>> vtor.check('ip_addr', '1.2.3.4.5')
951 Traceback (most recent call last):
952 VdtValueError: the value "1.2.3.4.5" is unacceptable.
953 >>> vtor.check('ip_addr', 0)
954 Traceback (most recent call last):
955 VdtTypeError: the value "0" is of the wrong type.
956 """
957 if not isinstance(value, str):
958 raise VdtTypeError(value)
959 value = value.strip()
960 try:
961 dottedQuadToNum(value)
962 except ValueError:
963 raise VdtValueError(value)
964 return value
967def is_list(value, min=None, max=None):
968 """
969 Check that the value is a list of values.
971 You can optionally specify the minimum and maximum number of members.
973 It does no check on list members.
975 >>> vtor.check('list', ())
976 []
977 >>> vtor.check('list', [])
978 []
979 >>> vtor.check('list', (1, 2))
980 [1, 2]
981 >>> vtor.check('list', [1, 2])
982 [1, 2]
983 >>> vtor.check('list(3)', (1, 2))
984 Traceback (most recent call last):
985 VdtValueTooShortError: the value "(1, 2)" is too short.
986 >>> vtor.check('list(max=5)', (1, 2, 3, 4, 5, 6))
987 Traceback (most recent call last):
988 VdtValueTooLongError: the value "(1, 2, 3, 4, 5, 6)" is too long.
989 >>> vtor.check('list(min=3, max=5)', (1, 2, 3, 4))
990 [1, 2, 3, 4]
991 >>> vtor.check('list', 0)
992 Traceback (most recent call last):
993 VdtTypeError: the value "0" is of the wrong type.
994 >>> vtor.check('list', '12')
995 Traceback (most recent call last):
996 VdtTypeError: the value "12" is of the wrong type.
997 """
998 (min_len, max_len) = _is_num_param(('min', 'max'), (min, max))
999 if isinstance(value, str):
1000 raise VdtTypeError(value)
1001 try:
1002 num_members = len(value)
1003 except TypeError:
1004 raise VdtTypeError(value)
1005 if min_len is not None and num_members < min_len:
1006 raise VdtValueTooShortError(value)
1007 if max_len is not None and num_members > max_len:
1008 raise VdtValueTooLongError(value)
1009 return list(value)
1012def is_tuple(value, min=None, max=None):
1013 """
1014 Check that the value is a tuple of values.
1016 You can optionally specify the minimum and maximum number of members.
1018 It does no check on members.
1020 >>> vtor.check('tuple', ())
1021 ()
1022 >>> vtor.check('tuple', [])
1023 ()
1024 >>> vtor.check('tuple', (1, 2))
1025 (1, 2)
1026 >>> vtor.check('tuple', [1, 2])
1027 (1, 2)
1028 >>> vtor.check('tuple(3)', (1, 2))
1029 Traceback (most recent call last):
1030 VdtValueTooShortError: the value "(1, 2)" is too short.
1031 >>> vtor.check('tuple(max=5)', (1, 2, 3, 4, 5, 6))
1032 Traceback (most recent call last):
1033 VdtValueTooLongError: the value "(1, 2, 3, 4, 5, 6)" is too long.
1034 >>> vtor.check('tuple(min=3, max=5)', (1, 2, 3, 4))
1035 (1, 2, 3, 4)
1036 >>> vtor.check('tuple', 0)
1037 Traceback (most recent call last):
1038 VdtTypeError: the value "0" is of the wrong type.
1039 >>> vtor.check('tuple', '12')
1040 Traceback (most recent call last):
1041 VdtTypeError: the value "12" is of the wrong type.
1042 """
1043 return tuple(is_list(value, min, max))
1046def is_string(value, min=None, max=None):
1047 """
1048 Check that the supplied value is a string.
1050 You can optionally specify the minimum and maximum number of members.
1052 >>> vtor.check('string', '0')
1053 '0'
1054 >>> vtor.check('string', 0)
1055 Traceback (most recent call last):
1056 VdtTypeError: the value "0" is of the wrong type.
1057 >>> vtor.check('string(2)', '12')
1058 '12'
1059 >>> vtor.check('string(2)', '1')
1060 Traceback (most recent call last):
1061 VdtValueTooShortError: the value "1" is too short.
1062 >>> vtor.check('string(min=2, max=3)', '123')
1063 '123'
1064 >>> vtor.check('string(min=2, max=3)', '1234')
1065 Traceback (most recent call last):
1066 VdtValueTooLongError: the value "1234" is too long.
1067 """
1068 if not isinstance(value, str): 1068 ↛ 1069line 1068 didn't jump to line 1069 because the condition on line 1068 was never true1bad
1069 raise VdtTypeError(value)
1070 (min_len, max_len) = _is_num_param(('min', 'max'), (min, max)) 1bad
1071 try: 1bad
1072 num_members = len(value) 1bad
1073 except TypeError:
1074 raise VdtTypeError(value)
1075 if min_len is not None and num_members < min_len: 1075 ↛ 1076line 1075 didn't jump to line 1076 because the condition on line 1075 was never true1bad
1076 raise VdtValueTooShortError(value)
1077 if max_len is not None and num_members > max_len: 1077 ↛ 1078line 1077 didn't jump to line 1078 because the condition on line 1077 was never true1bad
1078 raise VdtValueTooLongError(value)
1079 return value 1bad
1082def is_int_list(value, min=None, max=None):
1083 """
1084 Check that the value is a list of integers.
1086 You can optionally specify the minimum and maximum number of members.
1088 Each list member is checked that it is an integer.
1090 >>> vtor.check('int_list', ())
1091 []
1092 >>> vtor.check('int_list', [])
1093 []
1094 >>> vtor.check('int_list', (1, 2))
1095 [1, 2]
1096 >>> vtor.check('int_list', [1, 2])
1097 [1, 2]
1098 >>> vtor.check('int_list', [1, 'a'])
1099 Traceback (most recent call last):
1100 VdtTypeError: the value "a" is of the wrong type.
1101 """
1102 return [is_integer(mem) for mem in is_list(value, min, max)]
1105def is_bool_list(value, min=None, max=None):
1106 """
1107 Check that the value is a list of booleans.
1109 You can optionally specify the minimum and maximum number of members.
1111 Each list member is checked that it is a boolean.
1113 >>> vtor.check('bool_list', ())
1114 []
1115 >>> vtor.check('bool_list', [])
1116 []
1117 >>> check_res = vtor.check('bool_list', (True, False))
1118 >>> check_res == [True, False]
1119 1
1120 >>> check_res = vtor.check('bool_list', [True, False])
1121 >>> check_res == [True, False]
1122 1
1123 >>> vtor.check('bool_list', [True, 'a'])
1124 Traceback (most recent call last):
1125 VdtTypeError: the value "a" is of the wrong type.
1126 """
1127 return [is_boolean(mem) for mem in is_list(value, min, max)]
1130def is_float_list(value, min=None, max=None):
1131 """
1132 Check that the value is a list of floats.
1134 You can optionally specify the minimum and maximum number of members.
1136 Each list member is checked that it is a float.
1138 >>> vtor.check('float_list', ())
1139 []
1140 >>> vtor.check('float_list', [])
1141 []
1142 >>> vtor.check('float_list', (1, 2.0))
1143 [1.0, 2.0]
1144 >>> vtor.check('float_list', [1, 2.0])
1145 [1.0, 2.0]
1146 >>> vtor.check('float_list', [1, 'a'])
1147 Traceback (most recent call last):
1148 VdtTypeError: the value "a" is of the wrong type.
1149 """
1150 return [is_float(mem) for mem in is_list(value, min, max)]
1153def is_string_list(value, min=None, max=None):
1154 """
1155 Check that the value is a list of strings.
1157 You can optionally specify the minimum and maximum number of members.
1159 Each list member is checked that it is a string.
1161 >>> vtor.check('string_list', ())
1162 []
1163 >>> vtor.check('string_list', [])
1164 []
1165 >>> vtor.check('string_list', ('a', 'b'))
1166 ['a', 'b']
1167 >>> vtor.check('string_list', ['a', 1])
1168 Traceback (most recent call last):
1169 VdtTypeError: the value "1" is of the wrong type.
1170 >>> vtor.check('string_list', 'hello')
1171 Traceback (most recent call last):
1172 VdtTypeError: the value "hello" is of the wrong type.
1173 """
1174 if isinstance(value, str):
1175 raise VdtTypeError(value)
1176 return [is_string(mem) for mem in is_list(value, min, max)]
1179def is_ip_addr_list(value, min=None, max=None):
1180 """
1181 Check that the value is a list of IP addresses.
1183 You can optionally specify the minimum and maximum number of members.
1185 Each list member is checked that it is an IP address.
1187 >>> vtor.check('ip_addr_list', ())
1188 []
1189 >>> vtor.check('ip_addr_list', [])
1190 []
1191 >>> vtor.check('ip_addr_list', ('1.2.3.4', '5.6.7.8'))
1192 ['1.2.3.4', '5.6.7.8']
1193 >>> vtor.check('ip_addr_list', ['a'])
1194 Traceback (most recent call last):
1195 VdtValueError: the value "a" is unacceptable.
1196 """
1197 return [is_ip_addr(mem) for mem in is_list(value, min, max)]
1200def force_list(value, min=None, max=None):
1201 """
1202 Check that a value is a list, coercing strings into
1203 a list with one member. Useful where users forget the
1204 trailing comma that turns a single value into a list.
1206 You can optionally specify the minimum and maximum number of members.
1207 A minumum of greater than one will fail if the user only supplies a
1208 string.
1210 >>> vtor.check('force_list', ())
1211 []
1212 >>> vtor.check('force_list', [])
1213 []
1214 >>> vtor.check('force_list', 'hello')
1215 ['hello']
1216 """
1217 if not isinstance(value, (list, tuple)):
1218 value = [value]
1219 return is_list(value, min, max)
1223fun_dict = {
1224 'integer': is_integer,
1225 'float': is_float,
1226 'ip_addr': is_ip_addr,
1227 'string': is_string,
1228 'boolean': is_boolean,
1229}
1232def is_mixed_list(value, *args):
1233 """
1234 Check that the value is a list.
1235 Allow specifying the type of each member.
1236 Work on lists of specific lengths.
1238 You specify each member as a positional argument specifying type
1240 Each type should be one of the following strings :
1241 'integer', 'float', 'ip_addr', 'string', 'boolean'
1243 So you can specify a list of two strings, followed by
1244 two integers as :
1246 mixed_list('string', 'string', 'integer', 'integer')
1248 The length of the list must match the number of positional
1249 arguments you supply.
1251 >>> mix_str = "mixed_list('integer', 'float', 'ip_addr', 'string', 'boolean')"
1252 >>> check_res = vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', True))
1253 >>> check_res == [1, 2.0, '1.2.3.4', 'a', True]
1254 1
1255 >>> check_res = vtor.check(mix_str, ('1', '2.0', '1.2.3.4', 'a', 'True'))
1256 >>> check_res == [1, 2.0, '1.2.3.4', 'a', True]
1257 1
1258 >>> vtor.check(mix_str, ('b', 2.0, '1.2.3.4', 'a', True))
1259 Traceback (most recent call last):
1260 VdtTypeError: the value "b" is of the wrong type.
1261 >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a'))
1262 Traceback (most recent call last):
1263 VdtValueTooShortError: the value "(1, 2.0, '1.2.3.4', 'a')" is too short.
1264 >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', 1, 'b'))
1265 Traceback (most recent call last):
1266 VdtValueTooLongError: the value "(1, 2.0, '1.2.3.4', 'a', 1, 'b')" is too long.
1267 >>> vtor.check(mix_str, 0)
1268 Traceback (most recent call last):
1269 VdtTypeError: the value "0" is of the wrong type.
1271 >>> vtor.check('mixed_list("yoda")', ('a'))
1272 Traceback (most recent call last):
1273 VdtParamError: passed an incorrect value "KeyError('yoda',)" for parameter "'mixed_list'"
1274 """
1275 try:
1276 length = len(value)
1277 except TypeError:
1278 raise VdtTypeError(value)
1279 if length < len(args):
1280 raise VdtValueTooShortError(value)
1281 elif length > len(args):
1282 raise VdtValueTooLongError(value)
1283 try:
1284 return [fun_dict[arg](val) for arg, val in zip(args, value)]
1285 except KeyError as e:
1286 raise VdtParamError('mixed_list', e)
1289def is_option(value, *options):
1290 """
1291 This check matches the value to any of a set of options.
1293 >>> vtor.check('option("yoda", "jedi")', 'yoda')
1294 'yoda'
1295 >>> vtor.check('option("yoda", "jedi")', 'jed')
1296 Traceback (most recent call last):
1297 VdtValueError: the value "jed" is unacceptable.
1298 >>> vtor.check('option("yoda", "jedi")', 0)
1299 Traceback (most recent call last):
1300 VdtTypeError: the value "0" is of the wrong type.
1301 """
1302 if not isinstance(value, str):
1303 raise VdtTypeError(value)
1304 if not value in options:
1305 raise VdtValueError(value)
1306 return value
1309def _test(value, *args, **keywargs):
1310 """
1311 A function that exists for test purposes.
1313 >>> checks = [
1314 ... '3, 6, min=1, max=3, test=list(a, b, c)',
1315 ... '3',
1316 ... '3, 6',
1317 ... '3,',
1318 ... 'min=1, test="a b c"',
1319 ... 'min=5, test="a, b, c"',
1320 ... 'min=1, max=3, test="a, b, c"',
1321 ... 'min=-100, test=-99',
1322 ... 'min=1, max=3',
1323 ... '3, 6, test="36"',
1324 ... '3, 6, test="a, b, c"',
1325 ... '3, max=3, test=list("a", "b", "c")',
1326 ... '''3, max=3, test=list("'a'", 'b', "x=(c)")''',
1327 ... "test='x=fish(3)'",
1328 ... ]
1329 >>> v = Validator({'test': _test})
1330 >>> for entry in checks:
1331 ... pprint(v.check(('test(%s)' % entry), 3))
1332 (3, ('3', '6'), {'max': '3', 'min': '1', 'test': ['a', 'b', 'c']})
1333 (3, ('3',), {})
1334 (3, ('3', '6'), {})
1335 (3, ('3',), {})
1336 (3, (), {'min': '1', 'test': 'a b c'})
1337 (3, (), {'min': '5', 'test': 'a, b, c'})
1338 (3, (), {'max': '3', 'min': '1', 'test': 'a, b, c'})
1339 (3, (), {'min': '-100', 'test': '-99'})
1340 (3, (), {'max': '3', 'min': '1'})
1341 (3, ('3', '6'), {'test': '36'})
1342 (3, ('3', '6'), {'test': 'a, b, c'})
1343 (3, ('3',), {'max': '3', 'test': ['a', 'b', 'c']})
1344 (3, ('3',), {'max': '3', 'test': ["'a'", 'b', 'x=(c)']})
1345 (3, (), {'test': 'x=fish(3)'})
1347 >>> v = Validator()
1348 >>> v.check('integer(default=6)', '3')
1349 3
1350 >>> v.check('integer(default=6)', None, True)
1351 6
1352 >>> v.get_default_value('integer(default=6)')
1353 6
1354 >>> v.get_default_value('float(default=6)')
1355 6.0
1356 >>> v.get_default_value('pass(default=None)')
1357 >>> v.get_default_value("string(default='None')")
1358 'None'
1359 >>> v.get_default_value('pass')
1360 Traceback (most recent call last):
1361 KeyError: 'Check "pass" has no default value.'
1362 >>> v.get_default_value('pass(default=list(1, 2, 3, 4))')
1363 ['1', '2', '3', '4']
1365 >>> v = Validator()
1366 >>> v.check("pass(default=None)", None, True)
1367 >>> v.check("pass(default='None')", None, True)
1368 'None'
1369 >>> v.check('pass(default="None")', None, True)
1370 'None'
1371 >>> v.check('pass(default=list(1, 2, 3, 4))', None, True)
1372 ['1', '2', '3', '4']
1374 Bug test for unicode arguments
1375 >>> v = Validator()
1376 >>> v.check('string(min=4)', 'test') == 'test'
1377 True
1379 >>> v = Validator()
1380 >>> v.get_default_value('string(min=4, default="1234")') == '1234'
1381 True
1382 >>> v.check('string(min=4, default="1234")', 'test') == 'test'
1383 True
1385 >>> v = Validator()
1386 >>> default = v.get_default_value('string(default=None)')
1387 >>> default == None
1388 1
1389 """
1390 return (value, args, keywargs)
1393def _test2():
1394 """
1395 >>>
1396 >>> v = Validator()
1397 >>> v.get_default_value('string(default="#ff00dd")')
1398 '#ff00dd'
1399 >>> v.get_default_value('integer(default=3) # comment')
1400 3
1401 """
1403def _test3():
1404 r"""
1405 >>> vtor.check('string(default="")', '', missing=True)
1406 ''
1407 >>> vtor.check('string(default="\n")', '', missing=True)
1408 '\n'
1409 >>> print(vtor.check('string(default="\n")', '', missing=True))
1410 <BLANKLINE>
1411 <BLANKLINE>
1412 >>> vtor.check('string()', '\n')
1413 '\n'
1414 >>> vtor.check('string(default="\n\n\n")', '', missing=True)
1415 '\n\n\n'
1416 >>> vtor.check('string()', 'random \n text goes here\n\n')
1417 'random \n text goes here\n\n'
1418 >>> vtor.check('string(default=" \nrandom text\ngoes \n here\n\n ")',
1419 ... '', missing=True)
1420 ' \nrandom text\ngoes \n here\n\n '
1421 >>> vtor.check("string(default='\n\n\n')", '', missing=True)
1422 '\n\n\n'
1423 >>> vtor.check("option('\n','a','b',default='\n')", '', missing=True)
1424 '\n'
1425 >>> vtor.check("string_list()", ['foo', '\n', 'bar'])
1426 ['foo', '\n', 'bar']
1427 >>> vtor.check("string_list(default=list('\n'))", '', missing=True)
1428 ['\n']
1429 """
1432if __name__ == '__main__':
1433 # run the code tests in doctest format
1434 import sys
1435 import doctest
1436 m = sys.modules.get('__main__')
1437 globs = m.__dict__.copy()
1438 globs.update({
1439 'vtor': Validator(),
1440 })
1442 failures, tests = doctest.testmod(
1443 m, globs=globs,
1444 optionflags=doctest.IGNORE_EXCEPTION_DETAIL | doctest.ELLIPSIS)
1445 assert not failures, '{} failures out of {} tests'.format(failures, tests)