adding TestON
diff --git a/TestON/lib/configobj-4.7.2/validate.py b/TestON/lib/configobj-4.7.2/validate.py
new file mode 100644
index 0000000..73dbdb8
--- /dev/null
+++ b/TestON/lib/configobj-4.7.2/validate.py
@@ -0,0 +1,1450 @@
+# 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)