forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			1450 lines
		
	
	
	
		
			45 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			1450 lines
		
	
	
	
		
			45 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # validate.py
 | |
| # A Validator object
 | |
| # Copyright (C) 2005-2010 Michael Foord, Mark Andrews, Nicola Larosa
 | |
| # E-mail: fuzzyman AT voidspace DOT org DOT uk
 | |
| #         mark AT la-la DOT com
 | |
| #         nico AT tekNico DOT net
 | |
| 
 | |
| # This software is licensed under the terms of the BSD license.
 | |
| # http://www.voidspace.org.uk/python/license.shtml
 | |
| # Basically you're free to copy, modify, distribute and relicense it,
 | |
| # So long as you keep a copy of the license with it.
 | |
| 
 | |
| # Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
 | |
| # For information about bugfixes, updates and support, please join the
 | |
| # ConfigObj mailing list:
 | |
| # http://lists.sourceforge.net/lists/listinfo/configobj-develop
 | |
| # Comments, suggestions and bug reports welcome.
 | |
| 
 | |
| """
 | |
|     The Validator object is used to check that supplied values 
 | |
|     conform to a specification.
 | |
|     
 | |
|     The value can be supplied as a string - e.g. from a config file.
 | |
|     In this case the check will also *convert* the value to
 | |
|     the required type. This allows you to add validation
 | |
|     as a transparent layer to access data stored as strings.
 | |
|     The validation checks that the data is correct *and*
 | |
|     converts it to the expected type.
 | |
|     
 | |
|     Some standard checks are provided for basic data types.
 | |
|     Additional checks are easy to write. They can be
 | |
|     provided when the ``Validator`` is instantiated or
 | |
|     added afterwards.
 | |
|     
 | |
|     The standard functions work with the following basic data types :
 | |
|     
 | |
|     * integers
 | |
|     * floats
 | |
|     * booleans
 | |
|     * strings
 | |
|     * ip_addr
 | |
|     
 | |
|     plus lists of these datatypes
 | |
|     
 | |
|     Adding additional checks is done through coding simple functions.
 | |
|     
 | |
|     The full set of standard checks are : 
 | |
|     
 | |
|     * 'integer': matches integer values (including negative)
 | |
|                  Takes optional 'min' and 'max' arguments : ::
 | |
|     
 | |
|                    integer()
 | |
|                    integer(3, 9)  # any value from 3 to 9
 | |
|                    integer(min=0) # any positive value
 | |
|                    integer(max=9)
 | |
|     
 | |
|     * 'float': matches float values
 | |
|                Has the same parameters as the integer check.
 | |
|     
 | |
|     * 'boolean': matches boolean values - ``True`` or ``False``
 | |
|                  Acceptable string values for True are :
 | |
|                    true, on, yes, 1
 | |
|                  Acceptable string values for False are :
 | |
|                    false, off, no, 0
 | |
|     
 | |
|                  Any other value raises an error.
 | |
|     
 | |
|     * 'ip_addr': matches an Internet Protocol address, v.4, represented
 | |
|                  by a dotted-quad string, i.e. '1.2.3.4'.
 | |
|     
 | |
|     * 'string': matches any string.
 | |
|                 Takes optional keyword args 'min' and 'max'
 | |
|                 to specify min and max lengths of the string.
 | |
|     
 | |
|     * 'list': matches any list.
 | |
|               Takes optional keyword args 'min', and 'max' to specify min and
 | |
|               max sizes of the list. (Always returns a list.)
 | |
|     
 | |
|     * 'tuple': matches any tuple.
 | |
|               Takes optional keyword args 'min', and 'max' to specify min and
 | |
|               max sizes of the tuple. (Always returns a tuple.)
 | |
|     
 | |
|     * 'int_list': Matches a list of integers.
 | |
|                   Takes the same arguments as list.
 | |
|     
 | |
|     * 'float_list': Matches a list of floats.
 | |
|                     Takes the same arguments as list.
 | |
|     
 | |
|     * 'bool_list': Matches a list of boolean values.
 | |
|                    Takes the same arguments as list.
 | |
|     
 | |
|     * 'ip_addr_list': Matches a list of IP addresses.
 | |
|                      Takes the same arguments as list.
 | |
|     
 | |
|     * 'string_list': Matches a list of strings.
 | |
|                      Takes the same arguments as list.
 | |
|     
 | |
|     * 'mixed_list': Matches a list with different types in 
 | |
|                     specific positions. List size must match
 | |
|                     the number of arguments.
 | |
|     
 | |
|                     Each position can be one of :
 | |
|                     'integer', 'float', 'ip_addr', 'string', 'boolean'
 | |
|     
 | |
|                     So to specify a list with two strings followed
 | |
|                     by two integers, you write the check as : ::
 | |
|     
 | |
|                       mixed_list('string', 'string', 'integer', 'integer')
 | |
|     
 | |
|     * 'pass': This check matches everything ! It never fails
 | |
|               and the value is unchanged.
 | |
|     
 | |
|               It is also the default if no check is specified.
 | |
|     
 | |
|     * 'option': This check matches any from a list of options.
 | |
|                 You specify this check with : ::
 | |
|     
 | |
|                   option('option 1', 'option 2', 'option 3')
 | |
|     
 | |
|     You can supply a default value (returned if no value is supplied)
 | |
|     using the default keyword argument.
 | |
|     
 | |
|     You specify a list argument for default using a list constructor syntax in
 | |
|     the check : ::
 | |
|     
 | |
|         checkname(arg1, arg2, default=list('val 1', 'val 2', 'val 3'))
 | |
|     
 | |
|     A badly formatted set of arguments will raise a ``VdtParamError``.
 | |
| """
 | |
| 
 | |
| __version__ = '1.0.1'
 | |
| 
 | |
| 
 | |
| __all__ = (
 | |
|     '__version__',
 | |
|     'dottedQuadToNum',
 | |
|     'numToDottedQuad',
 | |
|     'ValidateError',
 | |
|     'VdtUnknownCheckError',
 | |
|     'VdtParamError',
 | |
|     'VdtTypeError',
 | |
|     'VdtValueError',
 | |
|     'VdtValueTooSmallError',
 | |
|     'VdtValueTooBigError',
 | |
|     'VdtValueTooShortError',
 | |
|     'VdtValueTooLongError',
 | |
|     'VdtMissingValue',
 | |
|     'Validator',
 | |
|     'is_integer',
 | |
|     'is_float',
 | |
|     'is_boolean',
 | |
|     'is_list',
 | |
|     'is_tuple',
 | |
|     'is_ip_addr',
 | |
|     'is_string',
 | |
|     'is_int_list',
 | |
|     'is_bool_list',
 | |
|     'is_float_list',
 | |
|     'is_string_list',
 | |
|     'is_ip_addr_list',
 | |
|     'is_mixed_list',
 | |
|     'is_option',
 | |
|     '__docformat__',
 | |
| )
 | |
| 
 | |
| 
 | |
| import re
 | |
| 
 | |
| 
 | |
| _list_arg = re.compile(r'''
 | |
|     (?:
 | |
|         ([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*list\(
 | |
|             (
 | |
|                 (?:
 | |
|                     \s*
 | |
|                     (?:
 | |
|                         (?:".*?")|              # double quotes
 | |
|                         (?:'.*?')|              # single quotes
 | |
|                         (?:[^'",\s\)][^,\)]*?)  # unquoted
 | |
|                     )
 | |
|                     \s*,\s*
 | |
|                 )*
 | |
|                 (?:
 | |
|                     (?:".*?")|              # double quotes
 | |
|                     (?:'.*?')|              # single quotes
 | |
|                     (?:[^'",\s\)][^,\)]*?)  # unquoted
 | |
|                 )?                          # last one
 | |
|             )
 | |
|         \)
 | |
|     )
 | |
| ''', re.VERBOSE | re.DOTALL)    # two groups
 | |
| 
 | |
| _list_members = re.compile(r'''
 | |
|     (
 | |
|         (?:".*?")|              # double quotes
 | |
|         (?:'.*?')|              # single quotes
 | |
|         (?:[^'",\s=][^,=]*?)       # unquoted
 | |
|     )
 | |
|     (?:
 | |
|     (?:\s*,\s*)|(?:\s*$)            # comma
 | |
|     )
 | |
| ''', re.VERBOSE | re.DOTALL)    # one group
 | |
| 
 | |
| _paramstring = r'''
 | |
|     (?:
 | |
|         (
 | |
|             (?:
 | |
|                 [a-zA-Z_][a-zA-Z0-9_]*\s*=\s*list\(
 | |
|                     (?:
 | |
|                         \s*
 | |
|                         (?:
 | |
|                             (?:".*?")|              # double quotes
 | |
|                             (?:'.*?')|              # single quotes
 | |
|                             (?:[^'",\s\)][^,\)]*?)       # unquoted
 | |
|                         )
 | |
|                         \s*,\s*
 | |
|                     )*
 | |
|                     (?:
 | |
|                         (?:".*?")|              # double quotes
 | |
|                         (?:'.*?')|              # single quotes
 | |
|                         (?:[^'",\s\)][^,\)]*?)       # unquoted
 | |
|                     )?                              # last one
 | |
|                 \)
 | |
|             )|
 | |
|             (?:
 | |
|                 (?:".*?")|              # double quotes
 | |
|                 (?:'.*?')|              # single quotes
 | |
|                 (?:[^'",\s=][^,=]*?)|       # unquoted
 | |
|                 (?:                         # keyword argument
 | |
|                     [a-zA-Z_][a-zA-Z0-9_]*\s*=\s*
 | |
|                     (?:
 | |
|                         (?:".*?")|              # double quotes
 | |
|                         (?:'.*?')|              # single quotes
 | |
|                         (?:[^'",\s=][^,=]*?)       # unquoted
 | |
|                     )
 | |
|                 )
 | |
|             )
 | |
|         )
 | |
|         (?:
 | |
|             (?:\s*,\s*)|(?:\s*$)            # comma
 | |
|         )
 | |
|     )
 | |
|     '''
 | |
| 
 | |
| _matchstring = '^%s*' % _paramstring
 | |
| 
 | |
| # Python pre 2.2.1 doesn't have bool
 | |
| try:
 | |
|     bool
 | |
| except NameError:
 | |
|     def bool(val):
 | |
|         """Simple boolean equivalent function. """
 | |
|         if val:
 | |
|             return 1
 | |
|         else:
 | |
|             return 0
 | |
| 
 | |
| 
 | |
| def dottedQuadToNum(ip):
 | |
|     """
 | |
|     Convert decimal dotted quad string to long integer
 | |
|     
 | |
|     >>> int(dottedQuadToNum('1 '))
 | |
|     1
 | |
|     >>> int(dottedQuadToNum(' 1.2'))
 | |
|     16777218
 | |
|     >>> int(dottedQuadToNum(' 1.2.3 '))
 | |
|     16908291
 | |
|     >>> int(dottedQuadToNum('1.2.3.4'))
 | |
|     16909060
 | |
|     >>> dottedQuadToNum('255.255.255.255')
 | |
|     4294967295L
 | |
|     >>> dottedQuadToNum('255.255.255.256')
 | |
|     Traceback (most recent call last):
 | |
|     ValueError: Not a good dotted-quad IP: 255.255.255.256
 | |
|     """
 | |
|     
 | |
|     # import here to avoid it when ip_addr values are not used
 | |
|     import socket, struct
 | |
|     
 | |
|     try:
 | |
|         return struct.unpack('!L',
 | |
|             socket.inet_aton(ip.strip()))[0]
 | |
|     except socket.error:
 | |
|         # bug in inet_aton, corrected in Python 2.4
 | |
|         if ip.strip() == '255.255.255.255':
 | |
|             return 0xFFFFFFFFL
 | |
|         else:
 | |
|             raise ValueError('Not a good dotted-quad IP: %s' % ip)
 | |
|     return
 | |
| 
 | |
| 
 | |
| def numToDottedQuad(num):
 | |
|     """
 | |
|     Convert long int to dotted quad string
 | |
|     
 | |
|     >>> numToDottedQuad(-1L)
 | |
|     Traceback (most recent call last):
 | |
|     ValueError: Not a good numeric IP: -1
 | |
|     >>> numToDottedQuad(1L)
 | |
|     '0.0.0.1'
 | |
|     >>> numToDottedQuad(16777218L)
 | |
|     '1.0.0.2'
 | |
|     >>> numToDottedQuad(16908291L)
 | |
|     '1.2.0.3'
 | |
|     >>> numToDottedQuad(16909060L)
 | |
|     '1.2.3.4'
 | |
|     >>> numToDottedQuad(4294967295L)
 | |
|     '255.255.255.255'
 | |
|     >>> numToDottedQuad(4294967296L)
 | |
|     Traceback (most recent call last):
 | |
|     ValueError: Not a good numeric IP: 4294967296
 | |
|     """
 | |
|     
 | |
|     # import here to avoid it when ip_addr values are not used
 | |
|     import socket, struct
 | |
|     
 | |
|     # no need to intercept here, 4294967295L is fine
 | |
|     if num > 4294967295L or num < 0:
 | |
|         raise ValueError('Not a good numeric IP: %s' % num)
 | |
|     try:
 | |
|         return socket.inet_ntoa(
 | |
|             struct.pack('!L', long(num)))
 | |
|     except (socket.error, struct.error, OverflowError):
 | |
|         raise ValueError('Not a good numeric IP: %s' % num)
 | |
| 
 | |
| 
 | |
| class ValidateError(Exception):
 | |
|     """
 | |
|     This error indicates that the check failed.
 | |
|     It can be the base class for more specific errors.
 | |
|     
 | |
|     Any check function that fails ought to raise this error.
 | |
|     (or a subclass)
 | |
|     
 | |
|     >>> raise ValidateError
 | |
|     Traceback (most recent call last):
 | |
|     ValidateError
 | |
|     """
 | |
| 
 | |
| 
 | |
| class VdtMissingValue(ValidateError):
 | |
|     """No value was supplied to a check that needed one."""
 | |
| 
 | |
| 
 | |
| class VdtUnknownCheckError(ValidateError):
 | |
|     """An unknown check function was requested"""
 | |
| 
 | |
|     def __init__(self, value):
 | |
|         """
 | |
|         >>> raise VdtUnknownCheckError('yoda')
 | |
|         Traceback (most recent call last):
 | |
|         VdtUnknownCheckError: the check "yoda" is unknown.
 | |
|         """
 | |
|         ValidateError.__init__(self, 'the check "%s" is unknown.' % (value,))
 | |
| 
 | |
| 
 | |
| class VdtParamError(SyntaxError):
 | |
|     """An incorrect parameter was passed"""
 | |
| 
 | |
|     def __init__(self, name, value):
 | |
|         """
 | |
|         >>> raise VdtParamError('yoda', 'jedi')
 | |
|         Traceback (most recent call last):
 | |
|         VdtParamError: passed an incorrect value "jedi" for parameter "yoda".
 | |
|         """
 | |
|         SyntaxError.__init__(self, 'passed an incorrect value "%s" for parameter "%s".' % (value, name))
 | |
| 
 | |
| 
 | |
| class VdtTypeError(ValidateError):
 | |
|     """The value supplied was of the wrong type"""
 | |
| 
 | |
|     def __init__(self, value):
 | |
|         """
 | |
|         >>> raise VdtTypeError('jedi')
 | |
|         Traceback (most recent call last):
 | |
|         VdtTypeError: the value "jedi" is of the wrong type.
 | |
|         """
 | |
|         ValidateError.__init__(self, 'the value "%s" is of the wrong type.' % (value,))
 | |
| 
 | |
| 
 | |
| class VdtValueError(ValidateError):
 | |
|     """The value supplied was of the correct type, but was not an allowed value."""
 | |
|     
 | |
|     def __init__(self, value):
 | |
|         """
 | |
|         >>> raise VdtValueError('jedi')
 | |
|         Traceback (most recent call last):
 | |
|         VdtValueError: the value "jedi" is unacceptable.
 | |
|         """
 | |
|         ValidateError.__init__(self, 'the value "%s" is unacceptable.' % (value,))
 | |
| 
 | |
| 
 | |
| class VdtValueTooSmallError(VdtValueError):
 | |
|     """The value supplied was of the correct type, but was too small."""
 | |
| 
 | |
|     def __init__(self, value):
 | |
|         """
 | |
|         >>> raise VdtValueTooSmallError('0')
 | |
|         Traceback (most recent call last):
 | |
|         VdtValueTooSmallError: the value "0" is too small.
 | |
|         """
 | |
|         ValidateError.__init__(self, 'the value "%s" is too small.' % (value,))
 | |
| 
 | |
| 
 | |
| class VdtValueTooBigError(VdtValueError):
 | |
|     """The value supplied was of the correct type, but was too big."""
 | |
| 
 | |
|     def __init__(self, value):
 | |
|         """
 | |
|         >>> raise VdtValueTooBigError('1')
 | |
|         Traceback (most recent call last):
 | |
|         VdtValueTooBigError: the value "1" is too big.
 | |
|         """
 | |
|         ValidateError.__init__(self, 'the value "%s" is too big.' % (value,))
 | |
| 
 | |
| 
 | |
| class VdtValueTooShortError(VdtValueError):
 | |
|     """The value supplied was of the correct type, but was too short."""
 | |
| 
 | |
|     def __init__(self, value):
 | |
|         """
 | |
|         >>> raise VdtValueTooShortError('jed')
 | |
|         Traceback (most recent call last):
 | |
|         VdtValueTooShortError: the value "jed" is too short.
 | |
|         """
 | |
|         ValidateError.__init__(
 | |
|             self,
 | |
|             'the value "%s" is too short.' % (value,))
 | |
| 
 | |
| 
 | |
| class VdtValueTooLongError(VdtValueError):
 | |
|     """The value supplied was of the correct type, but was too long."""
 | |
| 
 | |
|     def __init__(self, value):
 | |
|         """
 | |
|         >>> raise VdtValueTooLongError('jedie')
 | |
|         Traceback (most recent call last):
 | |
|         VdtValueTooLongError: the value "jedie" is too long.
 | |
|         """
 | |
|         ValidateError.__init__(self, 'the value "%s" is too long.' % (value,))
 | |
| 
 | |
| 
 | |
| class Validator(object):
 | |
|     """
 | |
|     Validator is an object that allows you to register a set of 'checks'.
 | |
|     These checks take input and test that it conforms to the check.
 | |
|     
 | |
|     This can also involve converting the value from a string into
 | |
|     the correct datatype.
 | |
|     
 | |
|     The ``check`` method takes an input string which configures which
 | |
|     check is to be used and applies that check to a supplied value.
 | |
|     
 | |
|     An example input string would be:
 | |
|     'int_range(param1, param2)'
 | |
|     
 | |
|     You would then provide something like:
 | |
|     
 | |
|     >>> def int_range_check(value, min, max):
 | |
|     ...     # turn min and max from strings to integers
 | |
|     ...     min = int(min)
 | |
|     ...     max = int(max)
 | |
|     ...     # check that value is of the correct type.
 | |
|     ...     # possible valid inputs are integers or strings
 | |
|     ...     # that represent integers
 | |
|     ...     if not isinstance(value, (int, long, basestring)):
 | |
|     ...         raise VdtTypeError(value)
 | |
|     ...     elif isinstance(value, basestring):
 | |
|     ...         # if we are given a string
 | |
|     ...         # attempt to convert to an integer
 | |
|     ...         try:
 | |
|     ...             value = int(value)
 | |
|     ...         except ValueError:
 | |
|     ...             raise VdtValueError(value)
 | |
|     ...     # check the value is between our constraints
 | |
|     ...     if not min <= value:
 | |
|     ...          raise VdtValueTooSmallError(value)
 | |
|     ...     if not value <= max:
 | |
|     ...          raise VdtValueTooBigError(value)
 | |
|     ...     return value
 | |
|     
 | |
|     >>> fdict = {'int_range': int_range_check}
 | |
|     >>> vtr1 = Validator(fdict)
 | |
|     >>> vtr1.check('int_range(20, 40)', '30')
 | |
|     30
 | |
|     >>> vtr1.check('int_range(20, 40)', '60')
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueTooBigError: the value "60" is too big.
 | |
|     
 | |
|     New functions can be added with : ::
 | |
|     
 | |
|     >>> vtr2 = Validator()       
 | |
|     >>> vtr2.functions['int_range'] = int_range_check
 | |
|     
 | |
|     Or by passing in a dictionary of functions when Validator 
 | |
|     is instantiated.
 | |
|     
 | |
|     Your functions *can* use keyword arguments,
 | |
|     but the first argument should always be 'value'.
 | |
|     
 | |
|     If the function doesn't take additional arguments,
 | |
|     the parentheses are optional in the check.
 | |
|     It can be written with either of : ::
 | |
|     
 | |
|         keyword = function_name
 | |
|         keyword = function_name()
 | |
|     
 | |
|     The first program to utilise Validator() was Michael Foord's
 | |
|     ConfigObj, an alternative to ConfigParser which supports lists and
 | |
|     can validate a config file using a config schema.
 | |
|     For more details on using Validator with ConfigObj see:
 | |
|     http://www.voidspace.org.uk/python/configobj.html
 | |
|     """
 | |
| 
 | |
|     # this regex does the initial parsing of the checks
 | |
|     _func_re = re.compile(r'(.+?)\((.*)\)', re.DOTALL)
 | |
| 
 | |
|     # this regex takes apart keyword arguments
 | |
|     _key_arg = re.compile(r'^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.*)$',  re.DOTALL)
 | |
| 
 | |
| 
 | |
|     # this regex finds keyword=list(....) type values
 | |
|     _list_arg = _list_arg
 | |
| 
 | |
|     # this regex takes individual values out of lists - in one pass
 | |
|     _list_members = _list_members
 | |
| 
 | |
|     # These regexes check a set of arguments for validity
 | |
|     # and then pull the members out
 | |
|     _paramfinder = re.compile(_paramstring, re.VERBOSE | re.DOTALL)
 | |
|     _matchfinder = re.compile(_matchstring, re.VERBOSE | re.DOTALL)
 | |
| 
 | |
| 
 | |
|     def __init__(self, functions=None):
 | |
|         """
 | |
|         >>> vtri = Validator()
 | |
|         """
 | |
|         self.functions = {
 | |
|             '': self._pass,
 | |
|             'integer': is_integer,
 | |
|             'float': is_float,
 | |
|             'boolean': is_boolean,
 | |
|             'ip_addr': is_ip_addr,
 | |
|             'string': is_string,
 | |
|             'list': is_list,
 | |
|             'tuple': is_tuple,
 | |
|             'int_list': is_int_list,
 | |
|             'float_list': is_float_list,
 | |
|             'bool_list': is_bool_list,
 | |
|             'ip_addr_list': is_ip_addr_list,
 | |
|             'string_list': is_string_list,
 | |
|             'mixed_list': is_mixed_list,
 | |
|             'pass': self._pass,
 | |
|             'option': is_option,
 | |
|             'force_list': force_list,
 | |
|         }
 | |
|         if functions is not None:
 | |
|             self.functions.update(functions)
 | |
|         # tekNico: for use by ConfigObj
 | |
|         self.baseErrorClass = ValidateError
 | |
|         self._cache = {}
 | |
| 
 | |
| 
 | |
|     def check(self, check, value, missing=False):
 | |
|         """
 | |
|         Usage: check(check, value)
 | |
|         
 | |
|         Arguments:
 | |
|             check: string representing check to apply (including arguments)
 | |
|             value: object to be checked
 | |
|         Returns value, converted to correct type if necessary
 | |
|         
 | |
|         If the check fails, raises a ``ValidateError`` subclass.
 | |
|         
 | |
|         >>> vtor.check('yoda', '')
 | |
|         Traceback (most recent call last):
 | |
|         VdtUnknownCheckError: the check "yoda" is unknown.
 | |
|         >>> vtor.check('yoda()', '')
 | |
|         Traceback (most recent call last):
 | |
|         VdtUnknownCheckError: the check "yoda" is unknown.
 | |
|         
 | |
|         >>> vtor.check('string(default="")', '', missing=True)
 | |
|         ''
 | |
|         """
 | |
|         fun_name, fun_args, fun_kwargs, default = self._parse_with_caching(check)
 | |
|             
 | |
|         if missing:
 | |
|             if default is None:
 | |
|                 # no information needed here - to be handled by caller
 | |
|                 raise VdtMissingValue()
 | |
|             value = self._handle_none(default)
 | |
|         
 | |
|         if value is None:
 | |
|             return None
 | |
|         
 | |
|         return self._check_value(value, fun_name, fun_args, fun_kwargs)
 | |
| 
 | |
| 
 | |
|     def _handle_none(self, value):
 | |
|         if value == 'None':
 | |
|             return None
 | |
|         elif value in ("'None'", '"None"'):
 | |
|             # Special case a quoted None
 | |
|             value = self._unquote(value)
 | |
|         return value
 | |
| 
 | |
| 
 | |
|     def _parse_with_caching(self, check):
 | |
|         if check in self._cache:
 | |
|             fun_name, fun_args, fun_kwargs, default = self._cache[check]
 | |
|             # We call list and dict below to work with *copies* of the data
 | |
|             # rather than the original (which are mutable of course)
 | |
|             fun_args = list(fun_args)
 | |
|             fun_kwargs = dict(fun_kwargs)
 | |
|         else:
 | |
|             fun_name, fun_args, fun_kwargs, default = self._parse_check(check)
 | |
|             fun_kwargs = dict([(str(key), value) for (key, value) in fun_kwargs.items()])
 | |
|             self._cache[check] = fun_name, list(fun_args), dict(fun_kwargs), default
 | |
|         return fun_name, fun_args, fun_kwargs, default
 | |
|         
 | |
|         
 | |
|     def _check_value(self, value, fun_name, fun_args, fun_kwargs):
 | |
|         try:
 | |
|             fun = self.functions[fun_name]
 | |
|         except KeyError:
 | |
|             raise VdtUnknownCheckError(fun_name)
 | |
|         else:
 | |
|             return fun(value, *fun_args, **fun_kwargs)
 | |
| 
 | |
| 
 | |
|     def _parse_check(self, check):
 | |
|         fun_match = self._func_re.match(check)
 | |
|         if fun_match:
 | |
|             fun_name = fun_match.group(1)
 | |
|             arg_string = fun_match.group(2)
 | |
|             arg_match = self._matchfinder.match(arg_string)
 | |
|             if arg_match is None:
 | |
|                 # Bad syntax
 | |
|                 raise VdtParamError('Bad syntax in check "%s".' % check)
 | |
|             fun_args = []
 | |
|             fun_kwargs = {}
 | |
|             # pull out args of group 2
 | |
|             for arg in self._paramfinder.findall(arg_string):
 | |
|                 # args may need whitespace removing (before removing quotes)
 | |
|                 arg = arg.strip()
 | |
|                 listmatch = self._list_arg.match(arg)
 | |
|                 if listmatch:
 | |
|                     key, val = self._list_handle(listmatch)
 | |
|                     fun_kwargs[key] = val
 | |
|                     continue
 | |
|                 keymatch = self._key_arg.match(arg)
 | |
|                 if keymatch:
 | |
|                     val = keymatch.group(2)
 | |
|                     if not val in ("'None'", '"None"'):
 | |
|                         # Special case a quoted None
 | |
|                         val = self._unquote(val)
 | |
|                     fun_kwargs[keymatch.group(1)] = val
 | |
|                     continue
 | |
|                 
 | |
|                 fun_args.append(self._unquote(arg))
 | |
|         else:
 | |
|             # allows for function names without (args)
 | |
|             return check, (), {}, None
 | |
| 
 | |
|         # Default must be deleted if the value is specified too,
 | |
|         # otherwise the check function will get a spurious "default" keyword arg
 | |
|         default = fun_kwargs.pop('default', None)
 | |
|         return fun_name, fun_args, fun_kwargs, default
 | |
| 
 | |
| 
 | |
|     def _unquote(self, val):
 | |
|         """Unquote a value if necessary."""
 | |
|         if (len(val) >= 2) and (val[0] in ("'", '"')) and (val[0] == val[-1]):
 | |
|             val = val[1:-1]
 | |
|         return val
 | |
| 
 | |
| 
 | |
|     def _list_handle(self, listmatch):
 | |
|         """Take apart a ``keyword=list('val, 'val')`` type string."""
 | |
|         out = []
 | |
|         name = listmatch.group(1)
 | |
|         args = listmatch.group(2)
 | |
|         for arg in self._list_members.findall(args):
 | |
|             out.append(self._unquote(arg))
 | |
|         return name, out
 | |
| 
 | |
| 
 | |
|     def _pass(self, value):
 | |
|         """
 | |
|         Dummy check that always passes
 | |
|         
 | |
|         >>> vtor.check('', 0)
 | |
|         0
 | |
|         >>> vtor.check('', '0')
 | |
|         '0'
 | |
|         """
 | |
|         return value
 | |
|     
 | |
|     
 | |
|     def get_default_value(self, check):
 | |
|         """
 | |
|         Given a check, return the default value for the check
 | |
|         (converted to the right type).
 | |
|         
 | |
|         If the check doesn't specify a default value then a
 | |
|         ``KeyError`` will be raised.
 | |
|         """
 | |
|         fun_name, fun_args, fun_kwargs, default = self._parse_with_caching(check)
 | |
|         if default is None:
 | |
|             raise KeyError('Check "%s" has no default value.' % check)
 | |
|         value = self._handle_none(default)
 | |
|         if value is None:
 | |
|             return value
 | |
|         return self._check_value(value, fun_name, fun_args, fun_kwargs)
 | |
| 
 | |
| 
 | |
| def _is_num_param(names, values, to_float=False):
 | |
|     """
 | |
|     Return numbers from inputs or raise VdtParamError.
 | |
|     
 | |
|     Lets ``None`` pass through.
 | |
|     Pass in keyword argument ``to_float=True`` to
 | |
|     use float for the conversion rather than int.
 | |
|     
 | |
|     >>> _is_num_param(('', ''), (0, 1.0))
 | |
|     [0, 1]
 | |
|     >>> _is_num_param(('', ''), (0, 1.0), to_float=True)
 | |
|     [0.0, 1.0]
 | |
|     >>> _is_num_param(('a'), ('a'))
 | |
|     Traceback (most recent call last):
 | |
|     VdtParamError: passed an incorrect value "a" for parameter "a".
 | |
|     """
 | |
|     fun = to_float and float or int
 | |
|     out_params = []
 | |
|     for (name, val) in zip(names, values):
 | |
|         if val is None:
 | |
|             out_params.append(val)
 | |
|         elif isinstance(val, (int, long, float, basestring)):
 | |
|             try:
 | |
|                 out_params.append(fun(val))
 | |
|             except ValueError, e:
 | |
|                 raise VdtParamError(name, val)
 | |
|         else:
 | |
|             raise VdtParamError(name, val)
 | |
|     return out_params
 | |
| 
 | |
| 
 | |
| # built in checks
 | |
| # you can override these by setting the appropriate name
 | |
| # in Validator.functions
 | |
| # note: if the params are specified wrongly in your input string,
 | |
| #       you will also raise errors.
 | |
| 
 | |
| def is_integer(value, min=None, max=None):
 | |
|     """
 | |
|     A check that tests that a given value is an integer (int, or long)
 | |
|     and optionally, between bounds. A negative value is accepted, while
 | |
|     a float will fail.
 | |
|     
 | |
|     If the value is a string, then the conversion is done - if possible.
 | |
|     Otherwise a VdtError is raised.
 | |
|     
 | |
|     >>> vtor.check('integer', '-1')
 | |
|     -1
 | |
|     >>> vtor.check('integer', '0')
 | |
|     0
 | |
|     >>> vtor.check('integer', 9)
 | |
|     9
 | |
|     >>> vtor.check('integer', 'a')
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "a" is of the wrong type.
 | |
|     >>> vtor.check('integer', '2.2')
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "2.2" is of the wrong type.
 | |
|     >>> vtor.check('integer(10)', '20')
 | |
|     20
 | |
|     >>> vtor.check('integer(max=20)', '15')
 | |
|     15
 | |
|     >>> vtor.check('integer(10)', '9')
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueTooSmallError: the value "9" is too small.
 | |
|     >>> vtor.check('integer(10)', 9)
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueTooSmallError: the value "9" is too small.
 | |
|     >>> vtor.check('integer(max=20)', '35')
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueTooBigError: the value "35" is too big.
 | |
|     >>> vtor.check('integer(max=20)', 35)
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueTooBigError: the value "35" is too big.
 | |
|     >>> vtor.check('integer(0, 9)', False)
 | |
|     0
 | |
|     """
 | |
|     (min_val, max_val) = _is_num_param(('min', 'max'), (min, max))
 | |
|     if not isinstance(value, (int, long, basestring)):
 | |
|         raise VdtTypeError(value)
 | |
|     if isinstance(value, basestring):
 | |
|         # if it's a string - does it represent an integer ?
 | |
|         try:
 | |
|             value = int(value)
 | |
|         except ValueError:
 | |
|             raise VdtTypeError(value)
 | |
|     if (min_val is not None) and (value < min_val):
 | |
|         raise VdtValueTooSmallError(value)
 | |
|     if (max_val is not None) and (value > max_val):
 | |
|         raise VdtValueTooBigError(value)
 | |
|     return value
 | |
| 
 | |
| 
 | |
| def is_float(value, min=None, max=None):
 | |
|     """
 | |
|     A check that tests that a given value is a float
 | |
|     (an integer will be accepted), and optionally - that it is between bounds.
 | |
|     
 | |
|     If the value is a string, then the conversion is done - if possible.
 | |
|     Otherwise a VdtError is raised.
 | |
|     
 | |
|     This can accept negative values.
 | |
|     
 | |
|     >>> vtor.check('float', '2')
 | |
|     2.0
 | |
|     
 | |
|     From now on we multiply the value to avoid comparing decimals
 | |
|     
 | |
|     >>> vtor.check('float', '-6.8') * 10
 | |
|     -68.0
 | |
|     >>> vtor.check('float', '12.2') * 10
 | |
|     122.0
 | |
|     >>> vtor.check('float', 8.4) * 10
 | |
|     84.0
 | |
|     >>> vtor.check('float', 'a')
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "a" is of the wrong type.
 | |
|     >>> vtor.check('float(10.1)', '10.2') * 10
 | |
|     102.0
 | |
|     >>> vtor.check('float(max=20.2)', '15.1') * 10
 | |
|     151.0
 | |
|     >>> vtor.check('float(10.0)', '9.0')
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueTooSmallError: the value "9.0" is too small.
 | |
|     >>> vtor.check('float(max=20.0)', '35.0')
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueTooBigError: the value "35.0" is too big.
 | |
|     """
 | |
|     (min_val, max_val) = _is_num_param(
 | |
|         ('min', 'max'), (min, max), to_float=True)
 | |
|     if not isinstance(value, (int, long, float, basestring)):
 | |
|         raise VdtTypeError(value)
 | |
|     if not isinstance(value, float):
 | |
|         # if it's a string - does it represent a float ?
 | |
|         try:
 | |
|             value = float(value)
 | |
|         except ValueError:
 | |
|             raise VdtTypeError(value)
 | |
|     if (min_val is not None) and (value < min_val):
 | |
|         raise VdtValueTooSmallError(value)
 | |
|     if (max_val is not None) and (value > max_val):
 | |
|         raise VdtValueTooBigError(value)
 | |
|     return value
 | |
| 
 | |
| 
 | |
| bool_dict = {
 | |
|     True: True, 'on': True, '1': True, 'true': True, 'yes': True, 
 | |
|     False: False, 'off': False, '0': False, 'false': False, 'no': False,
 | |
| }
 | |
| 
 | |
| 
 | |
| def is_boolean(value):
 | |
|     """
 | |
|     Check if the value represents a boolean.
 | |
|     
 | |
|     >>> vtor.check('boolean', 0)
 | |
|     0
 | |
|     >>> vtor.check('boolean', False)
 | |
|     0
 | |
|     >>> vtor.check('boolean', '0')
 | |
|     0
 | |
|     >>> vtor.check('boolean', 'off')
 | |
|     0
 | |
|     >>> vtor.check('boolean', 'false')
 | |
|     0
 | |
|     >>> vtor.check('boolean', 'no')
 | |
|     0
 | |
|     >>> vtor.check('boolean', 'nO')
 | |
|     0
 | |
|     >>> vtor.check('boolean', 'NO')
 | |
|     0
 | |
|     >>> vtor.check('boolean', 1)
 | |
|     1
 | |
|     >>> vtor.check('boolean', True)
 | |
|     1
 | |
|     >>> vtor.check('boolean', '1')
 | |
|     1
 | |
|     >>> vtor.check('boolean', 'on')
 | |
|     1
 | |
|     >>> vtor.check('boolean', 'true')
 | |
|     1
 | |
|     >>> vtor.check('boolean', 'yes')
 | |
|     1
 | |
|     >>> vtor.check('boolean', 'Yes')
 | |
|     1
 | |
|     >>> vtor.check('boolean', 'YES')
 | |
|     1
 | |
|     >>> vtor.check('boolean', '')
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "" is of the wrong type.
 | |
|     >>> vtor.check('boolean', 'up')
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "up" is of the wrong type.
 | |
|     
 | |
|     """
 | |
|     if isinstance(value, basestring):
 | |
|         try:
 | |
|             return bool_dict[value.lower()]
 | |
|         except KeyError:
 | |
|             raise VdtTypeError(value)
 | |
|     # we do an equality test rather than an identity test
 | |
|     # this ensures Python 2.2 compatibilty
 | |
|     # and allows 0 and 1 to represent True and False
 | |
|     if value == False:
 | |
|         return False
 | |
|     elif value == True:
 | |
|         return True
 | |
|     else:
 | |
|         raise VdtTypeError(value)
 | |
| 
 | |
| 
 | |
| def is_ip_addr(value):
 | |
|     """
 | |
|     Check that the supplied value is an Internet Protocol address, v.4,
 | |
|     represented by a dotted-quad string, i.e. '1.2.3.4'.
 | |
|     
 | |
|     >>> vtor.check('ip_addr', '1 ')
 | |
|     '1'
 | |
|     >>> vtor.check('ip_addr', ' 1.2')
 | |
|     '1.2'
 | |
|     >>> vtor.check('ip_addr', ' 1.2.3 ')
 | |
|     '1.2.3'
 | |
|     >>> vtor.check('ip_addr', '1.2.3.4')
 | |
|     '1.2.3.4'
 | |
|     >>> vtor.check('ip_addr', '0.0.0.0')
 | |
|     '0.0.0.0'
 | |
|     >>> vtor.check('ip_addr', '255.255.255.255')
 | |
|     '255.255.255.255'
 | |
|     >>> vtor.check('ip_addr', '255.255.255.256')
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueError: the value "255.255.255.256" is unacceptable.
 | |
|     >>> vtor.check('ip_addr', '1.2.3.4.5')
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueError: the value "1.2.3.4.5" is unacceptable.
 | |
|     >>> vtor.check('ip_addr', 0)
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "0" is of the wrong type.
 | |
|     """
 | |
|     if not isinstance(value, basestring):
 | |
|         raise VdtTypeError(value)
 | |
|     value = value.strip()
 | |
|     try:
 | |
|         dottedQuadToNum(value)
 | |
|     except ValueError:
 | |
|         raise VdtValueError(value)
 | |
|     return value
 | |
| 
 | |
| 
 | |
| def is_list(value, min=None, max=None):
 | |
|     """
 | |
|     Check that the value is a list of values.
 | |
|     
 | |
|     You can optionally specify the minimum and maximum number of members.
 | |
|     
 | |
|     It does no check on list members.
 | |
|     
 | |
|     >>> vtor.check('list', ())
 | |
|     []
 | |
|     >>> vtor.check('list', [])
 | |
|     []
 | |
|     >>> vtor.check('list', (1, 2))
 | |
|     [1, 2]
 | |
|     >>> vtor.check('list', [1, 2])
 | |
|     [1, 2]
 | |
|     >>> vtor.check('list(3)', (1, 2))
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueTooShortError: the value "(1, 2)" is too short.
 | |
|     >>> vtor.check('list(max=5)', (1, 2, 3, 4, 5, 6))
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueTooLongError: the value "(1, 2, 3, 4, 5, 6)" is too long.
 | |
|     >>> vtor.check('list(min=3, max=5)', (1, 2, 3, 4))
 | |
|     [1, 2, 3, 4]
 | |
|     >>> vtor.check('list', 0)
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "0" is of the wrong type.
 | |
|     >>> vtor.check('list', '12')
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "12" is of the wrong type.
 | |
|     """
 | |
|     (min_len, max_len) = _is_num_param(('min', 'max'), (min, max))
 | |
|     if isinstance(value, basestring):
 | |
|         raise VdtTypeError(value)
 | |
|     try:
 | |
|         num_members = len(value)
 | |
|     except TypeError:
 | |
|         raise VdtTypeError(value)
 | |
|     if min_len is not None and num_members < min_len:
 | |
|         raise VdtValueTooShortError(value)
 | |
|     if max_len is not None and num_members > max_len:
 | |
|         raise VdtValueTooLongError(value)
 | |
|     return list(value)
 | |
| 
 | |
| 
 | |
| def is_tuple(value, min=None, max=None):
 | |
|     """
 | |
|     Check that the value is a tuple of values.
 | |
|     
 | |
|     You can optionally specify the minimum and maximum number of members.
 | |
|     
 | |
|     It does no check on members.
 | |
|     
 | |
|     >>> vtor.check('tuple', ())
 | |
|     ()
 | |
|     >>> vtor.check('tuple', [])
 | |
|     ()
 | |
|     >>> vtor.check('tuple', (1, 2))
 | |
|     (1, 2)
 | |
|     >>> vtor.check('tuple', [1, 2])
 | |
|     (1, 2)
 | |
|     >>> vtor.check('tuple(3)', (1, 2))
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueTooShortError: the value "(1, 2)" is too short.
 | |
|     >>> vtor.check('tuple(max=5)', (1, 2, 3, 4, 5, 6))
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueTooLongError: the value "(1, 2, 3, 4, 5, 6)" is too long.
 | |
|     >>> vtor.check('tuple(min=3, max=5)', (1, 2, 3, 4))
 | |
|     (1, 2, 3, 4)
 | |
|     >>> vtor.check('tuple', 0)
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "0" is of the wrong type.
 | |
|     >>> vtor.check('tuple', '12')
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "12" is of the wrong type.
 | |
|     """
 | |
|     return tuple(is_list(value, min, max))
 | |
| 
 | |
| 
 | |
| def is_string(value, min=None, max=None):
 | |
|     """
 | |
|     Check that the supplied value is a string.
 | |
|     
 | |
|     You can optionally specify the minimum and maximum number of members.
 | |
|     
 | |
|     >>> vtor.check('string', '0')
 | |
|     '0'
 | |
|     >>> vtor.check('string', 0)
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "0" is of the wrong type.
 | |
|     >>> vtor.check('string(2)', '12')
 | |
|     '12'
 | |
|     >>> vtor.check('string(2)', '1')
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueTooShortError: the value "1" is too short.
 | |
|     >>> vtor.check('string(min=2, max=3)', '123')
 | |
|     '123'
 | |
|     >>> vtor.check('string(min=2, max=3)', '1234')
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueTooLongError: the value "1234" is too long.
 | |
|     """
 | |
|     if not isinstance(value, basestring):
 | |
|         raise VdtTypeError(value)
 | |
|     (min_len, max_len) = _is_num_param(('min', 'max'), (min, max))
 | |
|     try:
 | |
|         num_members = len(value)
 | |
|     except TypeError:
 | |
|         raise VdtTypeError(value)
 | |
|     if min_len is not None and num_members < min_len:
 | |
|         raise VdtValueTooShortError(value)
 | |
|     if max_len is not None and num_members > max_len:
 | |
|         raise VdtValueTooLongError(value)
 | |
|     return value
 | |
| 
 | |
| 
 | |
| def is_int_list(value, min=None, max=None):
 | |
|     """
 | |
|     Check that the value is a list of integers.
 | |
|     
 | |
|     You can optionally specify the minimum and maximum number of members.
 | |
|     
 | |
|     Each list member is checked that it is an integer.
 | |
|     
 | |
|     >>> vtor.check('int_list', ())
 | |
|     []
 | |
|     >>> vtor.check('int_list', [])
 | |
|     []
 | |
|     >>> vtor.check('int_list', (1, 2))
 | |
|     [1, 2]
 | |
|     >>> vtor.check('int_list', [1, 2])
 | |
|     [1, 2]
 | |
|     >>> vtor.check('int_list', [1, 'a'])
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "a" is of the wrong type.
 | |
|     """
 | |
|     return [is_integer(mem) for mem in is_list(value, min, max)]
 | |
| 
 | |
| 
 | |
| def is_bool_list(value, min=None, max=None):
 | |
|     """
 | |
|     Check that the value is a list of booleans.
 | |
|     
 | |
|     You can optionally specify the minimum and maximum number of members.
 | |
|     
 | |
|     Each list member is checked that it is a boolean.
 | |
|     
 | |
|     >>> vtor.check('bool_list', ())
 | |
|     []
 | |
|     >>> vtor.check('bool_list', [])
 | |
|     []
 | |
|     >>> check_res = vtor.check('bool_list', (True, False))
 | |
|     >>> check_res == [True, False]
 | |
|     1
 | |
|     >>> check_res = vtor.check('bool_list', [True, False])
 | |
|     >>> check_res == [True, False]
 | |
|     1
 | |
|     >>> vtor.check('bool_list', [True, 'a'])
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "a" is of the wrong type.
 | |
|     """
 | |
|     return [is_boolean(mem) for mem in is_list(value, min, max)]
 | |
| 
 | |
| 
 | |
| def is_float_list(value, min=None, max=None):
 | |
|     """
 | |
|     Check that the value is a list of floats.
 | |
|     
 | |
|     You can optionally specify the minimum and maximum number of members.
 | |
|     
 | |
|     Each list member is checked that it is a float.
 | |
|     
 | |
|     >>> vtor.check('float_list', ())
 | |
|     []
 | |
|     >>> vtor.check('float_list', [])
 | |
|     []
 | |
|     >>> vtor.check('float_list', (1, 2.0))
 | |
|     [1.0, 2.0]
 | |
|     >>> vtor.check('float_list', [1, 2.0])
 | |
|     [1.0, 2.0]
 | |
|     >>> vtor.check('float_list', [1, 'a'])
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "a" is of the wrong type.
 | |
|     """
 | |
|     return [is_float(mem) for mem in is_list(value, min, max)]
 | |
| 
 | |
| 
 | |
| def is_string_list(value, min=None, max=None):
 | |
|     """
 | |
|     Check that the value is a list of strings.
 | |
|     
 | |
|     You can optionally specify the minimum and maximum number of members.
 | |
|     
 | |
|     Each list member is checked that it is a string.
 | |
|     
 | |
|     >>> vtor.check('string_list', ())
 | |
|     []
 | |
|     >>> vtor.check('string_list', [])
 | |
|     []
 | |
|     >>> vtor.check('string_list', ('a', 'b'))
 | |
|     ['a', 'b']
 | |
|     >>> vtor.check('string_list', ['a', 1])
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "1" is of the wrong type.
 | |
|     >>> vtor.check('string_list', 'hello')
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "hello" is of the wrong type.
 | |
|     """
 | |
|     if isinstance(value, basestring):
 | |
|         raise VdtTypeError(value)
 | |
|     return [is_string(mem) for mem in is_list(value, min, max)]
 | |
| 
 | |
| 
 | |
| def is_ip_addr_list(value, min=None, max=None):
 | |
|     """
 | |
|     Check that the value is a list of IP addresses.
 | |
|     
 | |
|     You can optionally specify the minimum and maximum number of members.
 | |
|     
 | |
|     Each list member is checked that it is an IP address.
 | |
|     
 | |
|     >>> vtor.check('ip_addr_list', ())
 | |
|     []
 | |
|     >>> vtor.check('ip_addr_list', [])
 | |
|     []
 | |
|     >>> vtor.check('ip_addr_list', ('1.2.3.4', '5.6.7.8'))
 | |
|     ['1.2.3.4', '5.6.7.8']
 | |
|     >>> vtor.check('ip_addr_list', ['a'])
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueError: the value "a" is unacceptable.
 | |
|     """
 | |
|     return [is_ip_addr(mem) for mem in is_list(value, min, max)]
 | |
| 
 | |
| 
 | |
| def force_list(value, min=None, max=None):
 | |
|     """
 | |
|     Check that a value is a list, coercing strings into
 | |
|     a list with one member. Useful where users forget the
 | |
|     trailing comma that turns a single value into a list.
 | |
|     
 | |
|     You can optionally specify the minimum and maximum number of members.
 | |
|     A minumum of greater than one will fail if the user only supplies a
 | |
|     string.
 | |
|     
 | |
|     >>> vtor.check('force_list', ())
 | |
|     []
 | |
|     >>> vtor.check('force_list', [])
 | |
|     []
 | |
|     >>> vtor.check('force_list', 'hello')
 | |
|     ['hello']
 | |
|     """
 | |
|     if not isinstance(value, (list, tuple)):
 | |
|         value = [value]
 | |
|     return is_list(value, min, max)
 | |
|     
 | |
|     
 | |
| 
 | |
| fun_dict = {
 | |
|     'integer': is_integer,
 | |
|     'float': is_float,
 | |
|     'ip_addr': is_ip_addr,
 | |
|     'string': is_string,
 | |
|     'boolean': is_boolean,
 | |
| }
 | |
| 
 | |
| 
 | |
| def is_mixed_list(value, *args):
 | |
|     """
 | |
|     Check that the value is a list.
 | |
|     Allow specifying the type of each member.
 | |
|     Work on lists of specific lengths.
 | |
|     
 | |
|     You specify each member as a positional argument specifying type
 | |
|     
 | |
|     Each type should be one of the following strings :
 | |
|       'integer', 'float', 'ip_addr', 'string', 'boolean'
 | |
|     
 | |
|     So you can specify a list of two strings, followed by
 | |
|     two integers as :
 | |
|     
 | |
|       mixed_list('string', 'string', 'integer', 'integer')
 | |
|     
 | |
|     The length of the list must match the number of positional
 | |
|     arguments you supply.
 | |
|     
 | |
|     >>> mix_str = "mixed_list('integer', 'float', 'ip_addr', 'string', 'boolean')"
 | |
|     >>> check_res = vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', True))
 | |
|     >>> check_res == [1, 2.0, '1.2.3.4', 'a', True]
 | |
|     1
 | |
|     >>> check_res = vtor.check(mix_str, ('1', '2.0', '1.2.3.4', 'a', 'True'))
 | |
|     >>> check_res == [1, 2.0, '1.2.3.4', 'a', True]
 | |
|     1
 | |
|     >>> vtor.check(mix_str, ('b', 2.0, '1.2.3.4', 'a', True))
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "b" is of the wrong type.
 | |
|     >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a'))
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueTooShortError: the value "(1, 2.0, '1.2.3.4', 'a')" is too short.
 | |
|     >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', 1, 'b'))
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueTooLongError: the value "(1, 2.0, '1.2.3.4', 'a', 1, 'b')" is too long.
 | |
|     >>> vtor.check(mix_str, 0)
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "0" is of the wrong type.
 | |
|     
 | |
|     This test requires an elaborate setup, because of a change in error string
 | |
|     output from the interpreter between Python 2.2 and 2.3 .
 | |
|     
 | |
|     >>> res_seq = (
 | |
|     ...     'passed an incorrect value "',
 | |
|     ...     'yoda',
 | |
|     ...     '" for parameter "mixed_list".',
 | |
|     ... )
 | |
|     >>> res_str = "'".join(res_seq)
 | |
|     >>> try:
 | |
|     ...     vtor.check('mixed_list("yoda")', ('a'))
 | |
|     ... except VdtParamError, err:
 | |
|     ...     str(err) == res_str
 | |
|     1
 | |
|     """
 | |
|     try:
 | |
|         length = len(value)
 | |
|     except TypeError:
 | |
|         raise VdtTypeError(value)
 | |
|     if length < len(args):
 | |
|         raise VdtValueTooShortError(value)
 | |
|     elif length > len(args):
 | |
|         raise VdtValueTooLongError(value)
 | |
|     try:
 | |
|         return [fun_dict[arg](val) for arg, val in zip(args, value)]
 | |
|     except KeyError, e:
 | |
|         raise VdtParamError('mixed_list', e)
 | |
| 
 | |
| 
 | |
| def is_option(value, *options):
 | |
|     """
 | |
|     This check matches the value to any of a set of options.
 | |
|     
 | |
|     >>> vtor.check('option("yoda", "jedi")', 'yoda')
 | |
|     'yoda'
 | |
|     >>> vtor.check('option("yoda", "jedi")', 'jed')
 | |
|     Traceback (most recent call last):
 | |
|     VdtValueError: the value "jed" is unacceptable.
 | |
|     >>> vtor.check('option("yoda", "jedi")', 0)
 | |
|     Traceback (most recent call last):
 | |
|     VdtTypeError: the value "0" is of the wrong type.
 | |
|     """
 | |
|     if not isinstance(value, basestring):
 | |
|         raise VdtTypeError(value)
 | |
|     if not value in options:
 | |
|         raise VdtValueError(value)
 | |
|     return value
 | |
| 
 | |
| 
 | |
| def _test(value, *args, **keywargs):
 | |
|     """
 | |
|     A function that exists for test purposes.
 | |
|     
 | |
|     >>> checks = [
 | |
|     ...     '3, 6, min=1, max=3, test=list(a, b, c)',
 | |
|     ...     '3',
 | |
|     ...     '3, 6',
 | |
|     ...     '3,',
 | |
|     ...     'min=1, test="a b c"',
 | |
|     ...     'min=5, test="a, b, c"',
 | |
|     ...     'min=1, max=3, test="a, b, c"',
 | |
|     ...     'min=-100, test=-99',
 | |
|     ...     'min=1, max=3',
 | |
|     ...     '3, 6, test="36"',
 | |
|     ...     '3, 6, test="a, b, c"',
 | |
|     ...     '3, max=3, test=list("a", "b", "c")',
 | |
|     ...     '''3, max=3, test=list("'a'", 'b', "x=(c)")''',
 | |
|     ...     "test='x=fish(3)'",
 | |
|     ...    ]
 | |
|     >>> v = Validator({'test': _test})
 | |
|     >>> for entry in checks:
 | |
|     ...     print v.check(('test(%s)' % entry), 3)
 | |
|     (3, ('3', '6'), {'test': ['a', 'b', 'c'], 'max': '3', 'min': '1'})
 | |
|     (3, ('3',), {})
 | |
|     (3, ('3', '6'), {})
 | |
|     (3, ('3',), {})
 | |
|     (3, (), {'test': 'a b c', 'min': '1'})
 | |
|     (3, (), {'test': 'a, b, c', 'min': '5'})
 | |
|     (3, (), {'test': 'a, b, c', 'max': '3', 'min': '1'})
 | |
|     (3, (), {'test': '-99', 'min': '-100'})
 | |
|     (3, (), {'max': '3', 'min': '1'})
 | |
|     (3, ('3', '6'), {'test': '36'})
 | |
|     (3, ('3', '6'), {'test': 'a, b, c'})
 | |
|     (3, ('3',), {'test': ['a', 'b', 'c'], 'max': '3'})
 | |
|     (3, ('3',), {'test': ["'a'", 'b', 'x=(c)'], 'max': '3'})
 | |
|     (3, (), {'test': 'x=fish(3)'})
 | |
|     
 | |
|     >>> v = Validator()
 | |
|     >>> v.check('integer(default=6)', '3')
 | |
|     3
 | |
|     >>> v.check('integer(default=6)', None, True)
 | |
|     6
 | |
|     >>> v.get_default_value('integer(default=6)')
 | |
|     6
 | |
|     >>> v.get_default_value('float(default=6)')
 | |
|     6.0
 | |
|     >>> v.get_default_value('pass(default=None)')
 | |
|     >>> v.get_default_value("string(default='None')")
 | |
|     'None'
 | |
|     >>> v.get_default_value('pass')
 | |
|     Traceback (most recent call last):
 | |
|     KeyError: 'Check "pass" has no default value.'
 | |
|     >>> v.get_default_value('pass(default=list(1, 2, 3, 4))')
 | |
|     ['1', '2', '3', '4']
 | |
|     
 | |
|     >>> v = Validator()
 | |
|     >>> v.check("pass(default=None)", None, True)
 | |
|     >>> v.check("pass(default='None')", None, True)
 | |
|     'None'
 | |
|     >>> v.check('pass(default="None")', None, True)
 | |
|     'None'
 | |
|     >>> v.check('pass(default=list(1, 2, 3, 4))', None, True)
 | |
|     ['1', '2', '3', '4']
 | |
|     
 | |
|     Bug test for unicode arguments
 | |
|     >>> v = Validator()
 | |
|     >>> v.check(u'string(min=4)', u'test')
 | |
|     u'test'
 | |
|     
 | |
|     >>> v = Validator()
 | |
|     >>> v.get_default_value(u'string(min=4, default="1234")')
 | |
|     u'1234'
 | |
|     >>> v.check(u'string(min=4, default="1234")', u'test')
 | |
|     u'test'
 | |
|     
 | |
|     >>> v = Validator()
 | |
|     >>> default = v.get_default_value('string(default=None)')
 | |
|     >>> default == None
 | |
|     1
 | |
|     """
 | |
|     return (value, args, keywargs)
 | |
| 
 | |
| 
 | |
| def _test2():
 | |
|     """
 | |
|     >>> 
 | |
|     >>> v = Validator()
 | |
|     >>> v.get_default_value('string(default="#ff00dd")')
 | |
|     '#ff00dd'
 | |
|     >>> v.get_default_value('integer(default=3) # comment')
 | |
|     3
 | |
|     """
 | |
| 
 | |
| def _test3():
 | |
|     r"""
 | |
|     >>> vtor.check('string(default="")', '', missing=True)
 | |
|     ''
 | |
|     >>> vtor.check('string(default="\n")', '', missing=True)
 | |
|     '\n'
 | |
|     >>> print vtor.check('string(default="\n")', '', missing=True),
 | |
|     <BLANKLINE>
 | |
|     >>> vtor.check('string()', '\n')
 | |
|     '\n'
 | |
|     >>> vtor.check('string(default="\n\n\n")', '', missing=True)
 | |
|     '\n\n\n'
 | |
|     >>> vtor.check('string()', 'random \n text goes here\n\n')
 | |
|     'random \n text goes here\n\n'
 | |
|     >>> vtor.check('string(default=" \nrandom text\ngoes \n here\n\n ")',
 | |
|     ... '', missing=True)
 | |
|     ' \nrandom text\ngoes \n here\n\n '
 | |
|     >>> vtor.check("string(default='\n\n\n')", '', missing=True)
 | |
|     '\n\n\n'
 | |
|     >>> vtor.check("option('\n','a','b',default='\n')", '', missing=True)
 | |
|     '\n'
 | |
|     >>> vtor.check("string_list()", ['foo', '\n', 'bar'])
 | |
|     ['foo', '\n', 'bar']
 | |
|     >>> vtor.check("string_list(default=list('\n'))", '', missing=True)
 | |
|     ['\n']
 | |
|     """
 | |
|     
 | |
|     
 | |
| if __name__ == '__main__':
 | |
|     # run the code tests in doctest format
 | |
|     import sys
 | |
|     import doctest
 | |
|     m = sys.modules.get('__main__')
 | |
|     globs = m.__dict__.copy()
 | |
|     globs.update({
 | |
|         'vtor': Validator(),
 | |
|     })
 | |
|     doctest.testmod(m, globs=globs)
 | 
