1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/python/configobj/validate.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1450 @@ 1.4 +# validate.py 1.5 +# A Validator object 1.6 +# Copyright (C) 2005-2010 Michael Foord, Mark Andrews, Nicola Larosa 1.7 +# E-mail: fuzzyman AT voidspace DOT org DOT uk 1.8 +# mark AT la-la DOT com 1.9 +# nico AT tekNico DOT net 1.10 + 1.11 +# This software is licensed under the terms of the BSD license. 1.12 +# http://www.voidspace.org.uk/python/license.shtml 1.13 +# Basically you're free to copy, modify, distribute and relicense it, 1.14 +# So long as you keep a copy of the license with it. 1.15 + 1.16 +# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml 1.17 +# For information about bugfixes, updates and support, please join the 1.18 +# ConfigObj mailing list: 1.19 +# http://lists.sourceforge.net/lists/listinfo/configobj-develop 1.20 +# Comments, suggestions and bug reports welcome. 1.21 + 1.22 +""" 1.23 + The Validator object is used to check that supplied values 1.24 + conform to a specification. 1.25 + 1.26 + The value can be supplied as a string - e.g. from a config file. 1.27 + In this case the check will also *convert* the value to 1.28 + the required type. This allows you to add validation 1.29 + as a transparent layer to access data stored as strings. 1.30 + The validation checks that the data is correct *and* 1.31 + converts it to the expected type. 1.32 + 1.33 + Some standard checks are provided for basic data types. 1.34 + Additional checks are easy to write. They can be 1.35 + provided when the ``Validator`` is instantiated or 1.36 + added afterwards. 1.37 + 1.38 + The standard functions work with the following basic data types : 1.39 + 1.40 + * integers 1.41 + * floats 1.42 + * booleans 1.43 + * strings 1.44 + * ip_addr 1.45 + 1.46 + plus lists of these datatypes 1.47 + 1.48 + Adding additional checks is done through coding simple functions. 1.49 + 1.50 + The full set of standard checks are : 1.51 + 1.52 + * 'integer': matches integer values (including negative) 1.53 + Takes optional 'min' and 'max' arguments : :: 1.54 + 1.55 + integer() 1.56 + integer(3, 9) # any value from 3 to 9 1.57 + integer(min=0) # any positive value 1.58 + integer(max=9) 1.59 + 1.60 + * 'float': matches float values 1.61 + Has the same parameters as the integer check. 1.62 + 1.63 + * 'boolean': matches boolean values - ``True`` or ``False`` 1.64 + Acceptable string values for True are : 1.65 + true, on, yes, 1 1.66 + Acceptable string values for False are : 1.67 + false, off, no, 0 1.68 + 1.69 + Any other value raises an error. 1.70 + 1.71 + * 'ip_addr': matches an Internet Protocol address, v.4, represented 1.72 + by a dotted-quad string, i.e. '1.2.3.4'. 1.73 + 1.74 + * 'string': matches any string. 1.75 + Takes optional keyword args 'min' and 'max' 1.76 + to specify min and max lengths of the string. 1.77 + 1.78 + * 'list': matches any list. 1.79 + Takes optional keyword args 'min', and 'max' to specify min and 1.80 + max sizes of the list. (Always returns a list.) 1.81 + 1.82 + * 'tuple': matches any tuple. 1.83 + Takes optional keyword args 'min', and 'max' to specify min and 1.84 + max sizes of the tuple. (Always returns a tuple.) 1.85 + 1.86 + * 'int_list': Matches a list of integers. 1.87 + Takes the same arguments as list. 1.88 + 1.89 + * 'float_list': Matches a list of floats. 1.90 + Takes the same arguments as list. 1.91 + 1.92 + * 'bool_list': Matches a list of boolean values. 1.93 + Takes the same arguments as list. 1.94 + 1.95 + * 'ip_addr_list': Matches a list of IP addresses. 1.96 + Takes the same arguments as list. 1.97 + 1.98 + * 'string_list': Matches a list of strings. 1.99 + Takes the same arguments as list. 1.100 + 1.101 + * 'mixed_list': Matches a list with different types in 1.102 + specific positions. List size must match 1.103 + the number of arguments. 1.104 + 1.105 + Each position can be one of : 1.106 + 'integer', 'float', 'ip_addr', 'string', 'boolean' 1.107 + 1.108 + So to specify a list with two strings followed 1.109 + by two integers, you write the check as : :: 1.110 + 1.111 + mixed_list('string', 'string', 'integer', 'integer') 1.112 + 1.113 + * 'pass': This check matches everything ! It never fails 1.114 + and the value is unchanged. 1.115 + 1.116 + It is also the default if no check is specified. 1.117 + 1.118 + * 'option': This check matches any from a list of options. 1.119 + You specify this check with : :: 1.120 + 1.121 + option('option 1', 'option 2', 'option 3') 1.122 + 1.123 + You can supply a default value (returned if no value is supplied) 1.124 + using the default keyword argument. 1.125 + 1.126 + You specify a list argument for default using a list constructor syntax in 1.127 + the check : :: 1.128 + 1.129 + checkname(arg1, arg2, default=list('val 1', 'val 2', 'val 3')) 1.130 + 1.131 + A badly formatted set of arguments will raise a ``VdtParamError``. 1.132 +""" 1.133 + 1.134 +__version__ = '1.0.1' 1.135 + 1.136 + 1.137 +__all__ = ( 1.138 + '__version__', 1.139 + 'dottedQuadToNum', 1.140 + 'numToDottedQuad', 1.141 + 'ValidateError', 1.142 + 'VdtUnknownCheckError', 1.143 + 'VdtParamError', 1.144 + 'VdtTypeError', 1.145 + 'VdtValueError', 1.146 + 'VdtValueTooSmallError', 1.147 + 'VdtValueTooBigError', 1.148 + 'VdtValueTooShortError', 1.149 + 'VdtValueTooLongError', 1.150 + 'VdtMissingValue', 1.151 + 'Validator', 1.152 + 'is_integer', 1.153 + 'is_float', 1.154 + 'is_boolean', 1.155 + 'is_list', 1.156 + 'is_tuple', 1.157 + 'is_ip_addr', 1.158 + 'is_string', 1.159 + 'is_int_list', 1.160 + 'is_bool_list', 1.161 + 'is_float_list', 1.162 + 'is_string_list', 1.163 + 'is_ip_addr_list', 1.164 + 'is_mixed_list', 1.165 + 'is_option', 1.166 + '__docformat__', 1.167 +) 1.168 + 1.169 + 1.170 +import re 1.171 + 1.172 + 1.173 +_list_arg = re.compile(r''' 1.174 + (?: 1.175 + ([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*list\( 1.176 + ( 1.177 + (?: 1.178 + \s* 1.179 + (?: 1.180 + (?:".*?")| # double quotes 1.181 + (?:'.*?')| # single quotes 1.182 + (?:[^'",\s\)][^,\)]*?) # unquoted 1.183 + ) 1.184 + \s*,\s* 1.185 + )* 1.186 + (?: 1.187 + (?:".*?")| # double quotes 1.188 + (?:'.*?')| # single quotes 1.189 + (?:[^'",\s\)][^,\)]*?) # unquoted 1.190 + )? # last one 1.191 + ) 1.192 + \) 1.193 + ) 1.194 +''', re.VERBOSE | re.DOTALL) # two groups 1.195 + 1.196 +_list_members = re.compile(r''' 1.197 + ( 1.198 + (?:".*?")| # double quotes 1.199 + (?:'.*?')| # single quotes 1.200 + (?:[^'",\s=][^,=]*?) # unquoted 1.201 + ) 1.202 + (?: 1.203 + (?:\s*,\s*)|(?:\s*$) # comma 1.204 + ) 1.205 +''', re.VERBOSE | re.DOTALL) # one group 1.206 + 1.207 +_paramstring = r''' 1.208 + (?: 1.209 + ( 1.210 + (?: 1.211 + [a-zA-Z_][a-zA-Z0-9_]*\s*=\s*list\( 1.212 + (?: 1.213 + \s* 1.214 + (?: 1.215 + (?:".*?")| # double quotes 1.216 + (?:'.*?')| # single quotes 1.217 + (?:[^'",\s\)][^,\)]*?) # unquoted 1.218 + ) 1.219 + \s*,\s* 1.220 + )* 1.221 + (?: 1.222 + (?:".*?")| # double quotes 1.223 + (?:'.*?')| # single quotes 1.224 + (?:[^'",\s\)][^,\)]*?) # unquoted 1.225 + )? # last one 1.226 + \) 1.227 + )| 1.228 + (?: 1.229 + (?:".*?")| # double quotes 1.230 + (?:'.*?')| # single quotes 1.231 + (?:[^'",\s=][^,=]*?)| # unquoted 1.232 + (?: # keyword argument 1.233 + [a-zA-Z_][a-zA-Z0-9_]*\s*=\s* 1.234 + (?: 1.235 + (?:".*?")| # double quotes 1.236 + (?:'.*?')| # single quotes 1.237 + (?:[^'",\s=][^,=]*?) # unquoted 1.238 + ) 1.239 + ) 1.240 + ) 1.241 + ) 1.242 + (?: 1.243 + (?:\s*,\s*)|(?:\s*$) # comma 1.244 + ) 1.245 + ) 1.246 + ''' 1.247 + 1.248 +_matchstring = '^%s*' % _paramstring 1.249 + 1.250 +# Python pre 2.2.1 doesn't have bool 1.251 +try: 1.252 + bool 1.253 +except NameError: 1.254 + def bool(val): 1.255 + """Simple boolean equivalent function. """ 1.256 + if val: 1.257 + return 1 1.258 + else: 1.259 + return 0 1.260 + 1.261 + 1.262 +def dottedQuadToNum(ip): 1.263 + """ 1.264 + Convert decimal dotted quad string to long integer 1.265 + 1.266 + >>> int(dottedQuadToNum('1 ')) 1.267 + 1 1.268 + >>> int(dottedQuadToNum(' 1.2')) 1.269 + 16777218 1.270 + >>> int(dottedQuadToNum(' 1.2.3 ')) 1.271 + 16908291 1.272 + >>> int(dottedQuadToNum('1.2.3.4')) 1.273 + 16909060 1.274 + >>> dottedQuadToNum('255.255.255.255') 1.275 + 4294967295L 1.276 + >>> dottedQuadToNum('255.255.255.256') 1.277 + Traceback (most recent call last): 1.278 + ValueError: Not a good dotted-quad IP: 255.255.255.256 1.279 + """ 1.280 + 1.281 + # import here to avoid it when ip_addr values are not used 1.282 + import socket, struct 1.283 + 1.284 + try: 1.285 + return struct.unpack('!L', 1.286 + socket.inet_aton(ip.strip()))[0] 1.287 + except socket.error: 1.288 + # bug in inet_aton, corrected in Python 2.4 1.289 + if ip.strip() == '255.255.255.255': 1.290 + return 0xFFFFFFFFL 1.291 + else: 1.292 + raise ValueError('Not a good dotted-quad IP: %s' % ip) 1.293 + return 1.294 + 1.295 + 1.296 +def numToDottedQuad(num): 1.297 + """ 1.298 + Convert long int to dotted quad string 1.299 + 1.300 + >>> numToDottedQuad(-1L) 1.301 + Traceback (most recent call last): 1.302 + ValueError: Not a good numeric IP: -1 1.303 + >>> numToDottedQuad(1L) 1.304 + '0.0.0.1' 1.305 + >>> numToDottedQuad(16777218L) 1.306 + '1.0.0.2' 1.307 + >>> numToDottedQuad(16908291L) 1.308 + '1.2.0.3' 1.309 + >>> numToDottedQuad(16909060L) 1.310 + '1.2.3.4' 1.311 + >>> numToDottedQuad(4294967295L) 1.312 + '255.255.255.255' 1.313 + >>> numToDottedQuad(4294967296L) 1.314 + Traceback (most recent call last): 1.315 + ValueError: Not a good numeric IP: 4294967296 1.316 + """ 1.317 + 1.318 + # import here to avoid it when ip_addr values are not used 1.319 + import socket, struct 1.320 + 1.321 + # no need to intercept here, 4294967295L is fine 1.322 + if num > 4294967295L or num < 0: 1.323 + raise ValueError('Not a good numeric IP: %s' % num) 1.324 + try: 1.325 + return socket.inet_ntoa( 1.326 + struct.pack('!L', long(num))) 1.327 + except (socket.error, struct.error, OverflowError): 1.328 + raise ValueError('Not a good numeric IP: %s' % num) 1.329 + 1.330 + 1.331 +class ValidateError(Exception): 1.332 + """ 1.333 + This error indicates that the check failed. 1.334 + It can be the base class for more specific errors. 1.335 + 1.336 + Any check function that fails ought to raise this error. 1.337 + (or a subclass) 1.338 + 1.339 + >>> raise ValidateError 1.340 + Traceback (most recent call last): 1.341 + ValidateError 1.342 + """ 1.343 + 1.344 + 1.345 +class VdtMissingValue(ValidateError): 1.346 + """No value was supplied to a check that needed one.""" 1.347 + 1.348 + 1.349 +class VdtUnknownCheckError(ValidateError): 1.350 + """An unknown check function was requested""" 1.351 + 1.352 + def __init__(self, value): 1.353 + """ 1.354 + >>> raise VdtUnknownCheckError('yoda') 1.355 + Traceback (most recent call last): 1.356 + VdtUnknownCheckError: the check "yoda" is unknown. 1.357 + """ 1.358 + ValidateError.__init__(self, 'the check "%s" is unknown.' % (value,)) 1.359 + 1.360 + 1.361 +class VdtParamError(SyntaxError): 1.362 + """An incorrect parameter was passed""" 1.363 + 1.364 + def __init__(self, name, value): 1.365 + """ 1.366 + >>> raise VdtParamError('yoda', 'jedi') 1.367 + Traceback (most recent call last): 1.368 + VdtParamError: passed an incorrect value "jedi" for parameter "yoda". 1.369 + """ 1.370 + SyntaxError.__init__(self, 'passed an incorrect value "%s" for parameter "%s".' % (value, name)) 1.371 + 1.372 + 1.373 +class VdtTypeError(ValidateError): 1.374 + """The value supplied was of the wrong type""" 1.375 + 1.376 + def __init__(self, value): 1.377 + """ 1.378 + >>> raise VdtTypeError('jedi') 1.379 + Traceback (most recent call last): 1.380 + VdtTypeError: the value "jedi" is of the wrong type. 1.381 + """ 1.382 + ValidateError.__init__(self, 'the value "%s" is of the wrong type.' % (value,)) 1.383 + 1.384 + 1.385 +class VdtValueError(ValidateError): 1.386 + """The value supplied was of the correct type, but was not an allowed value.""" 1.387 + 1.388 + def __init__(self, value): 1.389 + """ 1.390 + >>> raise VdtValueError('jedi') 1.391 + Traceback (most recent call last): 1.392 + VdtValueError: the value "jedi" is unacceptable. 1.393 + """ 1.394 + ValidateError.__init__(self, 'the value "%s" is unacceptable.' % (value,)) 1.395 + 1.396 + 1.397 +class VdtValueTooSmallError(VdtValueError): 1.398 + """The value supplied was of the correct type, but was too small.""" 1.399 + 1.400 + def __init__(self, value): 1.401 + """ 1.402 + >>> raise VdtValueTooSmallError('0') 1.403 + Traceback (most recent call last): 1.404 + VdtValueTooSmallError: the value "0" is too small. 1.405 + """ 1.406 + ValidateError.__init__(self, 'the value "%s" is too small.' % (value,)) 1.407 + 1.408 + 1.409 +class VdtValueTooBigError(VdtValueError): 1.410 + """The value supplied was of the correct type, but was too big.""" 1.411 + 1.412 + def __init__(self, value): 1.413 + """ 1.414 + >>> raise VdtValueTooBigError('1') 1.415 + Traceback (most recent call last): 1.416 + VdtValueTooBigError: the value "1" is too big. 1.417 + """ 1.418 + ValidateError.__init__(self, 'the value "%s" is too big.' % (value,)) 1.419 + 1.420 + 1.421 +class VdtValueTooShortError(VdtValueError): 1.422 + """The value supplied was of the correct type, but was too short.""" 1.423 + 1.424 + def __init__(self, value): 1.425 + """ 1.426 + >>> raise VdtValueTooShortError('jed') 1.427 + Traceback (most recent call last): 1.428 + VdtValueTooShortError: the value "jed" is too short. 1.429 + """ 1.430 + ValidateError.__init__( 1.431 + self, 1.432 + 'the value "%s" is too short.' % (value,)) 1.433 + 1.434 + 1.435 +class VdtValueTooLongError(VdtValueError): 1.436 + """The value supplied was of the correct type, but was too long.""" 1.437 + 1.438 + def __init__(self, value): 1.439 + """ 1.440 + >>> raise VdtValueTooLongError('jedie') 1.441 + Traceback (most recent call last): 1.442 + VdtValueTooLongError: the value "jedie" is too long. 1.443 + """ 1.444 + ValidateError.__init__(self, 'the value "%s" is too long.' % (value,)) 1.445 + 1.446 + 1.447 +class Validator(object): 1.448 + """ 1.449 + Validator is an object that allows you to register a set of 'checks'. 1.450 + These checks take input and test that it conforms to the check. 1.451 + 1.452 + This can also involve converting the value from a string into 1.453 + the correct datatype. 1.454 + 1.455 + The ``check`` method takes an input string which configures which 1.456 + check is to be used and applies that check to a supplied value. 1.457 + 1.458 + An example input string would be: 1.459 + 'int_range(param1, param2)' 1.460 + 1.461 + You would then provide something like: 1.462 + 1.463 + >>> def int_range_check(value, min, max): 1.464 + ... # turn min and max from strings to integers 1.465 + ... min = int(min) 1.466 + ... max = int(max) 1.467 + ... # check that value is of the correct type. 1.468 + ... # possible valid inputs are integers or strings 1.469 + ... # that represent integers 1.470 + ... if not isinstance(value, (int, long, basestring)): 1.471 + ... raise VdtTypeError(value) 1.472 + ... elif isinstance(value, basestring): 1.473 + ... # if we are given a string 1.474 + ... # attempt to convert to an integer 1.475 + ... try: 1.476 + ... value = int(value) 1.477 + ... except ValueError: 1.478 + ... raise VdtValueError(value) 1.479 + ... # check the value is between our constraints 1.480 + ... if not min <= value: 1.481 + ... raise VdtValueTooSmallError(value) 1.482 + ... if not value <= max: 1.483 + ... raise VdtValueTooBigError(value) 1.484 + ... return value 1.485 + 1.486 + >>> fdict = {'int_range': int_range_check} 1.487 + >>> vtr1 = Validator(fdict) 1.488 + >>> vtr1.check('int_range(20, 40)', '30') 1.489 + 30 1.490 + >>> vtr1.check('int_range(20, 40)', '60') 1.491 + Traceback (most recent call last): 1.492 + VdtValueTooBigError: the value "60" is too big. 1.493 + 1.494 + New functions can be added with : :: 1.495 + 1.496 + >>> vtr2 = Validator() 1.497 + >>> vtr2.functions['int_range'] = int_range_check 1.498 + 1.499 + Or by passing in a dictionary of functions when Validator 1.500 + is instantiated. 1.501 + 1.502 + Your functions *can* use keyword arguments, 1.503 + but the first argument should always be 'value'. 1.504 + 1.505 + If the function doesn't take additional arguments, 1.506 + the parentheses are optional in the check. 1.507 + It can be written with either of : :: 1.508 + 1.509 + keyword = function_name 1.510 + keyword = function_name() 1.511 + 1.512 + The first program to utilise Validator() was Michael Foord's 1.513 + ConfigObj, an alternative to ConfigParser which supports lists and 1.514 + can validate a config file using a config schema. 1.515 + For more details on using Validator with ConfigObj see: 1.516 + http://www.voidspace.org.uk/python/configobj.html 1.517 + """ 1.518 + 1.519 + # this regex does the initial parsing of the checks 1.520 + _func_re = re.compile(r'(.+?)\((.*)\)', re.DOTALL) 1.521 + 1.522 + # this regex takes apart keyword arguments 1.523 + _key_arg = re.compile(r'^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.*)$', re.DOTALL) 1.524 + 1.525 + 1.526 + # this regex finds keyword=list(....) type values 1.527 + _list_arg = _list_arg 1.528 + 1.529 + # this regex takes individual values out of lists - in one pass 1.530 + _list_members = _list_members 1.531 + 1.532 + # These regexes check a set of arguments for validity 1.533 + # and then pull the members out 1.534 + _paramfinder = re.compile(_paramstring, re.VERBOSE | re.DOTALL) 1.535 + _matchfinder = re.compile(_matchstring, re.VERBOSE | re.DOTALL) 1.536 + 1.537 + 1.538 + def __init__(self, functions=None): 1.539 + """ 1.540 + >>> vtri = Validator() 1.541 + """ 1.542 + self.functions = { 1.543 + '': self._pass, 1.544 + 'integer': is_integer, 1.545 + 'float': is_float, 1.546 + 'boolean': is_boolean, 1.547 + 'ip_addr': is_ip_addr, 1.548 + 'string': is_string, 1.549 + 'list': is_list, 1.550 + 'tuple': is_tuple, 1.551 + 'int_list': is_int_list, 1.552 + 'float_list': is_float_list, 1.553 + 'bool_list': is_bool_list, 1.554 + 'ip_addr_list': is_ip_addr_list, 1.555 + 'string_list': is_string_list, 1.556 + 'mixed_list': is_mixed_list, 1.557 + 'pass': self._pass, 1.558 + 'option': is_option, 1.559 + 'force_list': force_list, 1.560 + } 1.561 + if functions is not None: 1.562 + self.functions.update(functions) 1.563 + # tekNico: for use by ConfigObj 1.564 + self.baseErrorClass = ValidateError 1.565 + self._cache = {} 1.566 + 1.567 + 1.568 + def check(self, check, value, missing=False): 1.569 + """ 1.570 + Usage: check(check, value) 1.571 + 1.572 + Arguments: 1.573 + check: string representing check to apply (including arguments) 1.574 + value: object to be checked 1.575 + Returns value, converted to correct type if necessary 1.576 + 1.577 + If the check fails, raises a ``ValidateError`` subclass. 1.578 + 1.579 + >>> vtor.check('yoda', '') 1.580 + Traceback (most recent call last): 1.581 + VdtUnknownCheckError: the check "yoda" is unknown. 1.582 + >>> vtor.check('yoda()', '') 1.583 + Traceback (most recent call last): 1.584 + VdtUnknownCheckError: the check "yoda" is unknown. 1.585 + 1.586 + >>> vtor.check('string(default="")', '', missing=True) 1.587 + '' 1.588 + """ 1.589 + fun_name, fun_args, fun_kwargs, default = self._parse_with_caching(check) 1.590 + 1.591 + if missing: 1.592 + if default is None: 1.593 + # no information needed here - to be handled by caller 1.594 + raise VdtMissingValue() 1.595 + value = self._handle_none(default) 1.596 + 1.597 + if value is None: 1.598 + return None 1.599 + 1.600 + return self._check_value(value, fun_name, fun_args, fun_kwargs) 1.601 + 1.602 + 1.603 + def _handle_none(self, value): 1.604 + if value == 'None': 1.605 + return None 1.606 + elif value in ("'None'", '"None"'): 1.607 + # Special case a quoted None 1.608 + value = self._unquote(value) 1.609 + return value 1.610 + 1.611 + 1.612 + def _parse_with_caching(self, check): 1.613 + if check in self._cache: 1.614 + fun_name, fun_args, fun_kwargs, default = self._cache[check] 1.615 + # We call list and dict below to work with *copies* of the data 1.616 + # rather than the original (which are mutable of course) 1.617 + fun_args = list(fun_args) 1.618 + fun_kwargs = dict(fun_kwargs) 1.619 + else: 1.620 + fun_name, fun_args, fun_kwargs, default = self._parse_check(check) 1.621 + fun_kwargs = dict([(str(key), value) for (key, value) in fun_kwargs.items()]) 1.622 + self._cache[check] = fun_name, list(fun_args), dict(fun_kwargs), default 1.623 + return fun_name, fun_args, fun_kwargs, default 1.624 + 1.625 + 1.626 + def _check_value(self, value, fun_name, fun_args, fun_kwargs): 1.627 + try: 1.628 + fun = self.functions[fun_name] 1.629 + except KeyError: 1.630 + raise VdtUnknownCheckError(fun_name) 1.631 + else: 1.632 + return fun(value, *fun_args, **fun_kwargs) 1.633 + 1.634 + 1.635 + def _parse_check(self, check): 1.636 + fun_match = self._func_re.match(check) 1.637 + if fun_match: 1.638 + fun_name = fun_match.group(1) 1.639 + arg_string = fun_match.group(2) 1.640 + arg_match = self._matchfinder.match(arg_string) 1.641 + if arg_match is None: 1.642 + # Bad syntax 1.643 + raise VdtParamError('Bad syntax in check "%s".' % check) 1.644 + fun_args = [] 1.645 + fun_kwargs = {} 1.646 + # pull out args of group 2 1.647 + for arg in self._paramfinder.findall(arg_string): 1.648 + # args may need whitespace removing (before removing quotes) 1.649 + arg = arg.strip() 1.650 + listmatch = self._list_arg.match(arg) 1.651 + if listmatch: 1.652 + key, val = self._list_handle(listmatch) 1.653 + fun_kwargs[key] = val 1.654 + continue 1.655 + keymatch = self._key_arg.match(arg) 1.656 + if keymatch: 1.657 + val = keymatch.group(2) 1.658 + if not val in ("'None'", '"None"'): 1.659 + # Special case a quoted None 1.660 + val = self._unquote(val) 1.661 + fun_kwargs[keymatch.group(1)] = val 1.662 + continue 1.663 + 1.664 + fun_args.append(self._unquote(arg)) 1.665 + else: 1.666 + # allows for function names without (args) 1.667 + return check, (), {}, None 1.668 + 1.669 + # Default must be deleted if the value is specified too, 1.670 + # otherwise the check function will get a spurious "default" keyword arg 1.671 + default = fun_kwargs.pop('default', None) 1.672 + return fun_name, fun_args, fun_kwargs, default 1.673 + 1.674 + 1.675 + def _unquote(self, val): 1.676 + """Unquote a value if necessary.""" 1.677 + if (len(val) >= 2) and (val[0] in ("'", '"')) and (val[0] == val[-1]): 1.678 + val = val[1:-1] 1.679 + return val 1.680 + 1.681 + 1.682 + def _list_handle(self, listmatch): 1.683 + """Take apart a ``keyword=list('val, 'val')`` type string.""" 1.684 + out = [] 1.685 + name = listmatch.group(1) 1.686 + args = listmatch.group(2) 1.687 + for arg in self._list_members.findall(args): 1.688 + out.append(self._unquote(arg)) 1.689 + return name, out 1.690 + 1.691 + 1.692 + def _pass(self, value): 1.693 + """ 1.694 + Dummy check that always passes 1.695 + 1.696 + >>> vtor.check('', 0) 1.697 + 0 1.698 + >>> vtor.check('', '0') 1.699 + '0' 1.700 + """ 1.701 + return value 1.702 + 1.703 + 1.704 + def get_default_value(self, check): 1.705 + """ 1.706 + Given a check, return the default value for the check 1.707 + (converted to the right type). 1.708 + 1.709 + If the check doesn't specify a default value then a 1.710 + ``KeyError`` will be raised. 1.711 + """ 1.712 + fun_name, fun_args, fun_kwargs, default = self._parse_with_caching(check) 1.713 + if default is None: 1.714 + raise KeyError('Check "%s" has no default value.' % check) 1.715 + value = self._handle_none(default) 1.716 + if value is None: 1.717 + return value 1.718 + return self._check_value(value, fun_name, fun_args, fun_kwargs) 1.719 + 1.720 + 1.721 +def _is_num_param(names, values, to_float=False): 1.722 + """ 1.723 + Return numbers from inputs or raise VdtParamError. 1.724 + 1.725 + Lets ``None`` pass through. 1.726 + Pass in keyword argument ``to_float=True`` to 1.727 + use float for the conversion rather than int. 1.728 + 1.729 + >>> _is_num_param(('', ''), (0, 1.0)) 1.730 + [0, 1] 1.731 + >>> _is_num_param(('', ''), (0, 1.0), to_float=True) 1.732 + [0.0, 1.0] 1.733 + >>> _is_num_param(('a'), ('a')) 1.734 + Traceback (most recent call last): 1.735 + VdtParamError: passed an incorrect value "a" for parameter "a". 1.736 + """ 1.737 + fun = to_float and float or int 1.738 + out_params = [] 1.739 + for (name, val) in zip(names, values): 1.740 + if val is None: 1.741 + out_params.append(val) 1.742 + elif isinstance(val, (int, long, float, basestring)): 1.743 + try: 1.744 + out_params.append(fun(val)) 1.745 + except ValueError, e: 1.746 + raise VdtParamError(name, val) 1.747 + else: 1.748 + raise VdtParamError(name, val) 1.749 + return out_params 1.750 + 1.751 + 1.752 +# built in checks 1.753 +# you can override these by setting the appropriate name 1.754 +# in Validator.functions 1.755 +# note: if the params are specified wrongly in your input string, 1.756 +# you will also raise errors. 1.757 + 1.758 +def is_integer(value, min=None, max=None): 1.759 + """ 1.760 + A check that tests that a given value is an integer (int, or long) 1.761 + and optionally, between bounds. A negative value is accepted, while 1.762 + a float will fail. 1.763 + 1.764 + If the value is a string, then the conversion is done - if possible. 1.765 + Otherwise a VdtError is raised. 1.766 + 1.767 + >>> vtor.check('integer', '-1') 1.768 + -1 1.769 + >>> vtor.check('integer', '0') 1.770 + 0 1.771 + >>> vtor.check('integer', 9) 1.772 + 9 1.773 + >>> vtor.check('integer', 'a') 1.774 + Traceback (most recent call last): 1.775 + VdtTypeError: the value "a" is of the wrong type. 1.776 + >>> vtor.check('integer', '2.2') 1.777 + Traceback (most recent call last): 1.778 + VdtTypeError: the value "2.2" is of the wrong type. 1.779 + >>> vtor.check('integer(10)', '20') 1.780 + 20 1.781 + >>> vtor.check('integer(max=20)', '15') 1.782 + 15 1.783 + >>> vtor.check('integer(10)', '9') 1.784 + Traceback (most recent call last): 1.785 + VdtValueTooSmallError: the value "9" is too small. 1.786 + >>> vtor.check('integer(10)', 9) 1.787 + Traceback (most recent call last): 1.788 + VdtValueTooSmallError: the value "9" is too small. 1.789 + >>> vtor.check('integer(max=20)', '35') 1.790 + Traceback (most recent call last): 1.791 + VdtValueTooBigError: the value "35" is too big. 1.792 + >>> vtor.check('integer(max=20)', 35) 1.793 + Traceback (most recent call last): 1.794 + VdtValueTooBigError: the value "35" is too big. 1.795 + >>> vtor.check('integer(0, 9)', False) 1.796 + 0 1.797 + """ 1.798 + (min_val, max_val) = _is_num_param(('min', 'max'), (min, max)) 1.799 + if not isinstance(value, (int, long, basestring)): 1.800 + raise VdtTypeError(value) 1.801 + if isinstance(value, basestring): 1.802 + # if it's a string - does it represent an integer ? 1.803 + try: 1.804 + value = int(value) 1.805 + except ValueError: 1.806 + raise VdtTypeError(value) 1.807 + if (min_val is not None) and (value < min_val): 1.808 + raise VdtValueTooSmallError(value) 1.809 + if (max_val is not None) and (value > max_val): 1.810 + raise VdtValueTooBigError(value) 1.811 + return value 1.812 + 1.813 + 1.814 +def is_float(value, min=None, max=None): 1.815 + """ 1.816 + A check that tests that a given value is a float 1.817 + (an integer will be accepted), and optionally - that it is between bounds. 1.818 + 1.819 + If the value is a string, then the conversion is done - if possible. 1.820 + Otherwise a VdtError is raised. 1.821 + 1.822 + This can accept negative values. 1.823 + 1.824 + >>> vtor.check('float', '2') 1.825 + 2.0 1.826 + 1.827 + From now on we multiply the value to avoid comparing decimals 1.828 + 1.829 + >>> vtor.check('float', '-6.8') * 10 1.830 + -68.0 1.831 + >>> vtor.check('float', '12.2') * 10 1.832 + 122.0 1.833 + >>> vtor.check('float', 8.4) * 10 1.834 + 84.0 1.835 + >>> vtor.check('float', 'a') 1.836 + Traceback (most recent call last): 1.837 + VdtTypeError: the value "a" is of the wrong type. 1.838 + >>> vtor.check('float(10.1)', '10.2') * 10 1.839 + 102.0 1.840 + >>> vtor.check('float(max=20.2)', '15.1') * 10 1.841 + 151.0 1.842 + >>> vtor.check('float(10.0)', '9.0') 1.843 + Traceback (most recent call last): 1.844 + VdtValueTooSmallError: the value "9.0" is too small. 1.845 + >>> vtor.check('float(max=20.0)', '35.0') 1.846 + Traceback (most recent call last): 1.847 + VdtValueTooBigError: the value "35.0" is too big. 1.848 + """ 1.849 + (min_val, max_val) = _is_num_param( 1.850 + ('min', 'max'), (min, max), to_float=True) 1.851 + if not isinstance(value, (int, long, float, basestring)): 1.852 + raise VdtTypeError(value) 1.853 + if not isinstance(value, float): 1.854 + # if it's a string - does it represent a float ? 1.855 + try: 1.856 + value = float(value) 1.857 + except ValueError: 1.858 + raise VdtTypeError(value) 1.859 + if (min_val is not None) and (value < min_val): 1.860 + raise VdtValueTooSmallError(value) 1.861 + if (max_val is not None) and (value > max_val): 1.862 + raise VdtValueTooBigError(value) 1.863 + return value 1.864 + 1.865 + 1.866 +bool_dict = { 1.867 + True: True, 'on': True, '1': True, 'true': True, 'yes': True, 1.868 + False: False, 'off': False, '0': False, 'false': False, 'no': False, 1.869 +} 1.870 + 1.871 + 1.872 +def is_boolean(value): 1.873 + """ 1.874 + Check if the value represents a boolean. 1.875 + 1.876 + >>> vtor.check('boolean', 0) 1.877 + 0 1.878 + >>> vtor.check('boolean', False) 1.879 + 0 1.880 + >>> vtor.check('boolean', '0') 1.881 + 0 1.882 + >>> vtor.check('boolean', 'off') 1.883 + 0 1.884 + >>> vtor.check('boolean', 'false') 1.885 + 0 1.886 + >>> vtor.check('boolean', 'no') 1.887 + 0 1.888 + >>> vtor.check('boolean', 'nO') 1.889 + 0 1.890 + >>> vtor.check('boolean', 'NO') 1.891 + 0 1.892 + >>> vtor.check('boolean', 1) 1.893 + 1 1.894 + >>> vtor.check('boolean', True) 1.895 + 1 1.896 + >>> vtor.check('boolean', '1') 1.897 + 1 1.898 + >>> vtor.check('boolean', 'on') 1.899 + 1 1.900 + >>> vtor.check('boolean', 'true') 1.901 + 1 1.902 + >>> vtor.check('boolean', 'yes') 1.903 + 1 1.904 + >>> vtor.check('boolean', 'Yes') 1.905 + 1 1.906 + >>> vtor.check('boolean', 'YES') 1.907 + 1 1.908 + >>> vtor.check('boolean', '') 1.909 + Traceback (most recent call last): 1.910 + VdtTypeError: the value "" is of the wrong type. 1.911 + >>> vtor.check('boolean', 'up') 1.912 + Traceback (most recent call last): 1.913 + VdtTypeError: the value "up" is of the wrong type. 1.914 + 1.915 + """ 1.916 + if isinstance(value, basestring): 1.917 + try: 1.918 + return bool_dict[value.lower()] 1.919 + except KeyError: 1.920 + raise VdtTypeError(value) 1.921 + # we do an equality test rather than an identity test 1.922 + # this ensures Python 2.2 compatibilty 1.923 + # and allows 0 and 1 to represent True and False 1.924 + if value == False: 1.925 + return False 1.926 + elif value == True: 1.927 + return True 1.928 + else: 1.929 + raise VdtTypeError(value) 1.930 + 1.931 + 1.932 +def is_ip_addr(value): 1.933 + """ 1.934 + Check that the supplied value is an Internet Protocol address, v.4, 1.935 + represented by a dotted-quad string, i.e. '1.2.3.4'. 1.936 + 1.937 + >>> vtor.check('ip_addr', '1 ') 1.938 + '1' 1.939 + >>> vtor.check('ip_addr', ' 1.2') 1.940 + '1.2' 1.941 + >>> vtor.check('ip_addr', ' 1.2.3 ') 1.942 + '1.2.3' 1.943 + >>> vtor.check('ip_addr', '1.2.3.4') 1.944 + '1.2.3.4' 1.945 + >>> vtor.check('ip_addr', '0.0.0.0') 1.946 + '0.0.0.0' 1.947 + >>> vtor.check('ip_addr', '255.255.255.255') 1.948 + '255.255.255.255' 1.949 + >>> vtor.check('ip_addr', '255.255.255.256') 1.950 + Traceback (most recent call last): 1.951 + VdtValueError: the value "255.255.255.256" is unacceptable. 1.952 + >>> vtor.check('ip_addr', '1.2.3.4.5') 1.953 + Traceback (most recent call last): 1.954 + VdtValueError: the value "1.2.3.4.5" is unacceptable. 1.955 + >>> vtor.check('ip_addr', 0) 1.956 + Traceback (most recent call last): 1.957 + VdtTypeError: the value "0" is of the wrong type. 1.958 + """ 1.959 + if not isinstance(value, basestring): 1.960 + raise VdtTypeError(value) 1.961 + value = value.strip() 1.962 + try: 1.963 + dottedQuadToNum(value) 1.964 + except ValueError: 1.965 + raise VdtValueError(value) 1.966 + return value 1.967 + 1.968 + 1.969 +def is_list(value, min=None, max=None): 1.970 + """ 1.971 + Check that the value is a list of values. 1.972 + 1.973 + You can optionally specify the minimum and maximum number of members. 1.974 + 1.975 + It does no check on list members. 1.976 + 1.977 + >>> vtor.check('list', ()) 1.978 + [] 1.979 + >>> vtor.check('list', []) 1.980 + [] 1.981 + >>> vtor.check('list', (1, 2)) 1.982 + [1, 2] 1.983 + >>> vtor.check('list', [1, 2]) 1.984 + [1, 2] 1.985 + >>> vtor.check('list(3)', (1, 2)) 1.986 + Traceback (most recent call last): 1.987 + VdtValueTooShortError: the value "(1, 2)" is too short. 1.988 + >>> vtor.check('list(max=5)', (1, 2, 3, 4, 5, 6)) 1.989 + Traceback (most recent call last): 1.990 + VdtValueTooLongError: the value "(1, 2, 3, 4, 5, 6)" is too long. 1.991 + >>> vtor.check('list(min=3, max=5)', (1, 2, 3, 4)) 1.992 + [1, 2, 3, 4] 1.993 + >>> vtor.check('list', 0) 1.994 + Traceback (most recent call last): 1.995 + VdtTypeError: the value "0" is of the wrong type. 1.996 + >>> vtor.check('list', '12') 1.997 + Traceback (most recent call last): 1.998 + VdtTypeError: the value "12" is of the wrong type. 1.999 + """ 1.1000 + (min_len, max_len) = _is_num_param(('min', 'max'), (min, max)) 1.1001 + if isinstance(value, basestring): 1.1002 + raise VdtTypeError(value) 1.1003 + try: 1.1004 + num_members = len(value) 1.1005 + except TypeError: 1.1006 + raise VdtTypeError(value) 1.1007 + if min_len is not None and num_members < min_len: 1.1008 + raise VdtValueTooShortError(value) 1.1009 + if max_len is not None and num_members > max_len: 1.1010 + raise VdtValueTooLongError(value) 1.1011 + return list(value) 1.1012 + 1.1013 + 1.1014 +def is_tuple(value, min=None, max=None): 1.1015 + """ 1.1016 + Check that the value is a tuple of values. 1.1017 + 1.1018 + You can optionally specify the minimum and maximum number of members. 1.1019 + 1.1020 + It does no check on members. 1.1021 + 1.1022 + >>> vtor.check('tuple', ()) 1.1023 + () 1.1024 + >>> vtor.check('tuple', []) 1.1025 + () 1.1026 + >>> vtor.check('tuple', (1, 2)) 1.1027 + (1, 2) 1.1028 + >>> vtor.check('tuple', [1, 2]) 1.1029 + (1, 2) 1.1030 + >>> vtor.check('tuple(3)', (1, 2)) 1.1031 + Traceback (most recent call last): 1.1032 + VdtValueTooShortError: the value "(1, 2)" is too short. 1.1033 + >>> vtor.check('tuple(max=5)', (1, 2, 3, 4, 5, 6)) 1.1034 + Traceback (most recent call last): 1.1035 + VdtValueTooLongError: the value "(1, 2, 3, 4, 5, 6)" is too long. 1.1036 + >>> vtor.check('tuple(min=3, max=5)', (1, 2, 3, 4)) 1.1037 + (1, 2, 3, 4) 1.1038 + >>> vtor.check('tuple', 0) 1.1039 + Traceback (most recent call last): 1.1040 + VdtTypeError: the value "0" is of the wrong type. 1.1041 + >>> vtor.check('tuple', '12') 1.1042 + Traceback (most recent call last): 1.1043 + VdtTypeError: the value "12" is of the wrong type. 1.1044 + """ 1.1045 + return tuple(is_list(value, min, max)) 1.1046 + 1.1047 + 1.1048 +def is_string(value, min=None, max=None): 1.1049 + """ 1.1050 + Check that the supplied value is a string. 1.1051 + 1.1052 + You can optionally specify the minimum and maximum number of members. 1.1053 + 1.1054 + >>> vtor.check('string', '0') 1.1055 + '0' 1.1056 + >>> vtor.check('string', 0) 1.1057 + Traceback (most recent call last): 1.1058 + VdtTypeError: the value "0" is of the wrong type. 1.1059 + >>> vtor.check('string(2)', '12') 1.1060 + '12' 1.1061 + >>> vtor.check('string(2)', '1') 1.1062 + Traceback (most recent call last): 1.1063 + VdtValueTooShortError: the value "1" is too short. 1.1064 + >>> vtor.check('string(min=2, max=3)', '123') 1.1065 + '123' 1.1066 + >>> vtor.check('string(min=2, max=3)', '1234') 1.1067 + Traceback (most recent call last): 1.1068 + VdtValueTooLongError: the value "1234" is too long. 1.1069 + """ 1.1070 + if not isinstance(value, basestring): 1.1071 + raise VdtTypeError(value) 1.1072 + (min_len, max_len) = _is_num_param(('min', 'max'), (min, max)) 1.1073 + try: 1.1074 + num_members = len(value) 1.1075 + except TypeError: 1.1076 + raise VdtTypeError(value) 1.1077 + if min_len is not None and num_members < min_len: 1.1078 + raise VdtValueTooShortError(value) 1.1079 + if max_len is not None and num_members > max_len: 1.1080 + raise VdtValueTooLongError(value) 1.1081 + return value 1.1082 + 1.1083 + 1.1084 +def is_int_list(value, min=None, max=None): 1.1085 + """ 1.1086 + Check that the value is a list of integers. 1.1087 + 1.1088 + You can optionally specify the minimum and maximum number of members. 1.1089 + 1.1090 + Each list member is checked that it is an integer. 1.1091 + 1.1092 + >>> vtor.check('int_list', ()) 1.1093 + [] 1.1094 + >>> vtor.check('int_list', []) 1.1095 + [] 1.1096 + >>> vtor.check('int_list', (1, 2)) 1.1097 + [1, 2] 1.1098 + >>> vtor.check('int_list', [1, 2]) 1.1099 + [1, 2] 1.1100 + >>> vtor.check('int_list', [1, 'a']) 1.1101 + Traceback (most recent call last): 1.1102 + VdtTypeError: the value "a" is of the wrong type. 1.1103 + """ 1.1104 + return [is_integer(mem) for mem in is_list(value, min, max)] 1.1105 + 1.1106 + 1.1107 +def is_bool_list(value, min=None, max=None): 1.1108 + """ 1.1109 + Check that the value is a list of booleans. 1.1110 + 1.1111 + You can optionally specify the minimum and maximum number of members. 1.1112 + 1.1113 + Each list member is checked that it is a boolean. 1.1114 + 1.1115 + >>> vtor.check('bool_list', ()) 1.1116 + [] 1.1117 + >>> vtor.check('bool_list', []) 1.1118 + [] 1.1119 + >>> check_res = vtor.check('bool_list', (True, False)) 1.1120 + >>> check_res == [True, False] 1.1121 + 1 1.1122 + >>> check_res = vtor.check('bool_list', [True, False]) 1.1123 + >>> check_res == [True, False] 1.1124 + 1 1.1125 + >>> vtor.check('bool_list', [True, 'a']) 1.1126 + Traceback (most recent call last): 1.1127 + VdtTypeError: the value "a" is of the wrong type. 1.1128 + """ 1.1129 + return [is_boolean(mem) for mem in is_list(value, min, max)] 1.1130 + 1.1131 + 1.1132 +def is_float_list(value, min=None, max=None): 1.1133 + """ 1.1134 + Check that the value is a list of floats. 1.1135 + 1.1136 + You can optionally specify the minimum and maximum number of members. 1.1137 + 1.1138 + Each list member is checked that it is a float. 1.1139 + 1.1140 + >>> vtor.check('float_list', ()) 1.1141 + [] 1.1142 + >>> vtor.check('float_list', []) 1.1143 + [] 1.1144 + >>> vtor.check('float_list', (1, 2.0)) 1.1145 + [1.0, 2.0] 1.1146 + >>> vtor.check('float_list', [1, 2.0]) 1.1147 + [1.0, 2.0] 1.1148 + >>> vtor.check('float_list', [1, 'a']) 1.1149 + Traceback (most recent call last): 1.1150 + VdtTypeError: the value "a" is of the wrong type. 1.1151 + """ 1.1152 + return [is_float(mem) for mem in is_list(value, min, max)] 1.1153 + 1.1154 + 1.1155 +def is_string_list(value, min=None, max=None): 1.1156 + """ 1.1157 + Check that the value is a list of strings. 1.1158 + 1.1159 + You can optionally specify the minimum and maximum number of members. 1.1160 + 1.1161 + Each list member is checked that it is a string. 1.1162 + 1.1163 + >>> vtor.check('string_list', ()) 1.1164 + [] 1.1165 + >>> vtor.check('string_list', []) 1.1166 + [] 1.1167 + >>> vtor.check('string_list', ('a', 'b')) 1.1168 + ['a', 'b'] 1.1169 + >>> vtor.check('string_list', ['a', 1]) 1.1170 + Traceback (most recent call last): 1.1171 + VdtTypeError: the value "1" is of the wrong type. 1.1172 + >>> vtor.check('string_list', 'hello') 1.1173 + Traceback (most recent call last): 1.1174 + VdtTypeError: the value "hello" is of the wrong type. 1.1175 + """ 1.1176 + if isinstance(value, basestring): 1.1177 + raise VdtTypeError(value) 1.1178 + return [is_string(mem) for mem in is_list(value, min, max)] 1.1179 + 1.1180 + 1.1181 +def is_ip_addr_list(value, min=None, max=None): 1.1182 + """ 1.1183 + Check that the value is a list of IP addresses. 1.1184 + 1.1185 + You can optionally specify the minimum and maximum number of members. 1.1186 + 1.1187 + Each list member is checked that it is an IP address. 1.1188 + 1.1189 + >>> vtor.check('ip_addr_list', ()) 1.1190 + [] 1.1191 + >>> vtor.check('ip_addr_list', []) 1.1192 + [] 1.1193 + >>> vtor.check('ip_addr_list', ('1.2.3.4', '5.6.7.8')) 1.1194 + ['1.2.3.4', '5.6.7.8'] 1.1195 + >>> vtor.check('ip_addr_list', ['a']) 1.1196 + Traceback (most recent call last): 1.1197 + VdtValueError: the value "a" is unacceptable. 1.1198 + """ 1.1199 + return [is_ip_addr(mem) for mem in is_list(value, min, max)] 1.1200 + 1.1201 + 1.1202 +def force_list(value, min=None, max=None): 1.1203 + """ 1.1204 + Check that a value is a list, coercing strings into 1.1205 + a list with one member. Useful where users forget the 1.1206 + trailing comma that turns a single value into a list. 1.1207 + 1.1208 + You can optionally specify the minimum and maximum number of members. 1.1209 + A minumum of greater than one will fail if the user only supplies a 1.1210 + string. 1.1211 + 1.1212 + >>> vtor.check('force_list', ()) 1.1213 + [] 1.1214 + >>> vtor.check('force_list', []) 1.1215 + [] 1.1216 + >>> vtor.check('force_list', 'hello') 1.1217 + ['hello'] 1.1218 + """ 1.1219 + if not isinstance(value, (list, tuple)): 1.1220 + value = [value] 1.1221 + return is_list(value, min, max) 1.1222 + 1.1223 + 1.1224 + 1.1225 +fun_dict = { 1.1226 + 'integer': is_integer, 1.1227 + 'float': is_float, 1.1228 + 'ip_addr': is_ip_addr, 1.1229 + 'string': is_string, 1.1230 + 'boolean': is_boolean, 1.1231 +} 1.1232 + 1.1233 + 1.1234 +def is_mixed_list(value, *args): 1.1235 + """ 1.1236 + Check that the value is a list. 1.1237 + Allow specifying the type of each member. 1.1238 + Work on lists of specific lengths. 1.1239 + 1.1240 + You specify each member as a positional argument specifying type 1.1241 + 1.1242 + Each type should be one of the following strings : 1.1243 + 'integer', 'float', 'ip_addr', 'string', 'boolean' 1.1244 + 1.1245 + So you can specify a list of two strings, followed by 1.1246 + two integers as : 1.1247 + 1.1248 + mixed_list('string', 'string', 'integer', 'integer') 1.1249 + 1.1250 + The length of the list must match the number of positional 1.1251 + arguments you supply. 1.1252 + 1.1253 + >>> mix_str = "mixed_list('integer', 'float', 'ip_addr', 'string', 'boolean')" 1.1254 + >>> check_res = vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', True)) 1.1255 + >>> check_res == [1, 2.0, '1.2.3.4', 'a', True] 1.1256 + 1 1.1257 + >>> check_res = vtor.check(mix_str, ('1', '2.0', '1.2.3.4', 'a', 'True')) 1.1258 + >>> check_res == [1, 2.0, '1.2.3.4', 'a', True] 1.1259 + 1 1.1260 + >>> vtor.check(mix_str, ('b', 2.0, '1.2.3.4', 'a', True)) 1.1261 + Traceback (most recent call last): 1.1262 + VdtTypeError: the value "b" is of the wrong type. 1.1263 + >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a')) 1.1264 + Traceback (most recent call last): 1.1265 + VdtValueTooShortError: the value "(1, 2.0, '1.2.3.4', 'a')" is too short. 1.1266 + >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', 1, 'b')) 1.1267 + Traceback (most recent call last): 1.1268 + VdtValueTooLongError: the value "(1, 2.0, '1.2.3.4', 'a', 1, 'b')" is too long. 1.1269 + >>> vtor.check(mix_str, 0) 1.1270 + Traceback (most recent call last): 1.1271 + VdtTypeError: the value "0" is of the wrong type. 1.1272 + 1.1273 + This test requires an elaborate setup, because of a change in error string 1.1274 + output from the interpreter between Python 2.2 and 2.3 . 1.1275 + 1.1276 + >>> res_seq = ( 1.1277 + ... 'passed an incorrect value "', 1.1278 + ... 'yoda', 1.1279 + ... '" for parameter "mixed_list".', 1.1280 + ... ) 1.1281 + >>> res_str = "'".join(res_seq) 1.1282 + >>> try: 1.1283 + ... vtor.check('mixed_list("yoda")', ('a')) 1.1284 + ... except VdtParamError, err: 1.1285 + ... str(err) == res_str 1.1286 + 1 1.1287 + """ 1.1288 + try: 1.1289 + length = len(value) 1.1290 + except TypeError: 1.1291 + raise VdtTypeError(value) 1.1292 + if length < len(args): 1.1293 + raise VdtValueTooShortError(value) 1.1294 + elif length > len(args): 1.1295 + raise VdtValueTooLongError(value) 1.1296 + try: 1.1297 + return [fun_dict[arg](val) for arg, val in zip(args, value)] 1.1298 + except KeyError, e: 1.1299 + raise VdtParamError('mixed_list', e) 1.1300 + 1.1301 + 1.1302 +def is_option(value, *options): 1.1303 + """ 1.1304 + This check matches the value to any of a set of options. 1.1305 + 1.1306 + >>> vtor.check('option("yoda", "jedi")', 'yoda') 1.1307 + 'yoda' 1.1308 + >>> vtor.check('option("yoda", "jedi")', 'jed') 1.1309 + Traceback (most recent call last): 1.1310 + VdtValueError: the value "jed" is unacceptable. 1.1311 + >>> vtor.check('option("yoda", "jedi")', 0) 1.1312 + Traceback (most recent call last): 1.1313 + VdtTypeError: the value "0" is of the wrong type. 1.1314 + """ 1.1315 + if not isinstance(value, basestring): 1.1316 + raise VdtTypeError(value) 1.1317 + if not value in options: 1.1318 + raise VdtValueError(value) 1.1319 + return value 1.1320 + 1.1321 + 1.1322 +def _test(value, *args, **keywargs): 1.1323 + """ 1.1324 + A function that exists for test purposes. 1.1325 + 1.1326 + >>> checks = [ 1.1327 + ... '3, 6, min=1, max=3, test=list(a, b, c)', 1.1328 + ... '3', 1.1329 + ... '3, 6', 1.1330 + ... '3,', 1.1331 + ... 'min=1, test="a b c"', 1.1332 + ... 'min=5, test="a, b, c"', 1.1333 + ... 'min=1, max=3, test="a, b, c"', 1.1334 + ... 'min=-100, test=-99', 1.1335 + ... 'min=1, max=3', 1.1336 + ... '3, 6, test="36"', 1.1337 + ... '3, 6, test="a, b, c"', 1.1338 + ... '3, max=3, test=list("a", "b", "c")', 1.1339 + ... '''3, max=3, test=list("'a'", 'b', "x=(c)")''', 1.1340 + ... "test='x=fish(3)'", 1.1341 + ... ] 1.1342 + >>> v = Validator({'test': _test}) 1.1343 + >>> for entry in checks: 1.1344 + ... print v.check(('test(%s)' % entry), 3) 1.1345 + (3, ('3', '6'), {'test': ['a', 'b', 'c'], 'max': '3', 'min': '1'}) 1.1346 + (3, ('3',), {}) 1.1347 + (3, ('3', '6'), {}) 1.1348 + (3, ('3',), {}) 1.1349 + (3, (), {'test': 'a b c', 'min': '1'}) 1.1350 + (3, (), {'test': 'a, b, c', 'min': '5'}) 1.1351 + (3, (), {'test': 'a, b, c', 'max': '3', 'min': '1'}) 1.1352 + (3, (), {'test': '-99', 'min': '-100'}) 1.1353 + (3, (), {'max': '3', 'min': '1'}) 1.1354 + (3, ('3', '6'), {'test': '36'}) 1.1355 + (3, ('3', '6'), {'test': 'a, b, c'}) 1.1356 + (3, ('3',), {'test': ['a', 'b', 'c'], 'max': '3'}) 1.1357 + (3, ('3',), {'test': ["'a'", 'b', 'x=(c)'], 'max': '3'}) 1.1358 + (3, (), {'test': 'x=fish(3)'}) 1.1359 + 1.1360 + >>> v = Validator() 1.1361 + >>> v.check('integer(default=6)', '3') 1.1362 + 3 1.1363 + >>> v.check('integer(default=6)', None, True) 1.1364 + 6 1.1365 + >>> v.get_default_value('integer(default=6)') 1.1366 + 6 1.1367 + >>> v.get_default_value('float(default=6)') 1.1368 + 6.0 1.1369 + >>> v.get_default_value('pass(default=None)') 1.1370 + >>> v.get_default_value("string(default='None')") 1.1371 + 'None' 1.1372 + >>> v.get_default_value('pass') 1.1373 + Traceback (most recent call last): 1.1374 + KeyError: 'Check "pass" has no default value.' 1.1375 + >>> v.get_default_value('pass(default=list(1, 2, 3, 4))') 1.1376 + ['1', '2', '3', '4'] 1.1377 + 1.1378 + >>> v = Validator() 1.1379 + >>> v.check("pass(default=None)", None, True) 1.1380 + >>> v.check("pass(default='None')", None, True) 1.1381 + 'None' 1.1382 + >>> v.check('pass(default="None")', None, True) 1.1383 + 'None' 1.1384 + >>> v.check('pass(default=list(1, 2, 3, 4))', None, True) 1.1385 + ['1', '2', '3', '4'] 1.1386 + 1.1387 + Bug test for unicode arguments 1.1388 + >>> v = Validator() 1.1389 + >>> v.check(u'string(min=4)', u'test') 1.1390 + u'test' 1.1391 + 1.1392 + >>> v = Validator() 1.1393 + >>> v.get_default_value(u'string(min=4, default="1234")') 1.1394 + u'1234' 1.1395 + >>> v.check(u'string(min=4, default="1234")', u'test') 1.1396 + u'test' 1.1397 + 1.1398 + >>> v = Validator() 1.1399 + >>> default = v.get_default_value('string(default=None)') 1.1400 + >>> default == None 1.1401 + 1 1.1402 + """ 1.1403 + return (value, args, keywargs) 1.1404 + 1.1405 + 1.1406 +def _test2(): 1.1407 + """ 1.1408 + >>> 1.1409 + >>> v = Validator() 1.1410 + >>> v.get_default_value('string(default="#ff00dd")') 1.1411 + '#ff00dd' 1.1412 + >>> v.get_default_value('integer(default=3) # comment') 1.1413 + 3 1.1414 + """ 1.1415 + 1.1416 +def _test3(): 1.1417 + r""" 1.1418 + >>> vtor.check('string(default="")', '', missing=True) 1.1419 + '' 1.1420 + >>> vtor.check('string(default="\n")', '', missing=True) 1.1421 + '\n' 1.1422 + >>> print vtor.check('string(default="\n")', '', missing=True), 1.1423 + <BLANKLINE> 1.1424 + >>> vtor.check('string()', '\n') 1.1425 + '\n' 1.1426 + >>> vtor.check('string(default="\n\n\n")', '', missing=True) 1.1427 + '\n\n\n' 1.1428 + >>> vtor.check('string()', 'random \n text goes here\n\n') 1.1429 + 'random \n text goes here\n\n' 1.1430 + >>> vtor.check('string(default=" \nrandom text\ngoes \n here\n\n ")', 1.1431 + ... '', missing=True) 1.1432 + ' \nrandom text\ngoes \n here\n\n ' 1.1433 + >>> vtor.check("string(default='\n\n\n')", '', missing=True) 1.1434 + '\n\n\n' 1.1435 + >>> vtor.check("option('\n','a','b',default='\n')", '', missing=True) 1.1436 + '\n' 1.1437 + >>> vtor.check("string_list()", ['foo', '\n', 'bar']) 1.1438 + ['foo', '\n', 'bar'] 1.1439 + >>> vtor.check("string_list(default=list('\n'))", '', missing=True) 1.1440 + ['\n'] 1.1441 + """ 1.1442 + 1.1443 + 1.1444 +if __name__ == '__main__': 1.1445 + # run the code tests in doctest format 1.1446 + import sys 1.1447 + import doctest 1.1448 + m = sys.modules.get('__main__') 1.1449 + globs = m.__dict__.copy() 1.1450 + globs.update({ 1.1451 + 'vtor': Validator(), 1.1452 + }) 1.1453 + doctest.testmod(m, globs=globs)