Coverage for src/robotide/preferences/configobj/src/configobj/validate.py: 55%

271 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-05-06 10:40 +0100

1# validate.py 

2# A Validator object 

3# Copyright (C) 2005-2014: 

4# (name) : (email) 

5# Michael Foord: fuzzyman AT voidspace DOT org DOT uk 

6# Mark Andrews: mark AT la-la DOT com 

7# Nicola Larosa: nico AT tekNico DOT net 

8# Rob Dennis: rdennis AT gmail DOT com 

9# Eli Courtwright: eli AT courtwright DOT org 

10 

11# This software is licensed under the terms of the BSD license. 

12# http://opensource.org/licenses/BSD-3-Clause 

13 

14# ConfigObj 5 - main repository for documentation and issue tracking: 

15# https://github.com/DiffSK/configobj 

16 

17""" 

18 The Validator object is used to check that supplied values  

19 conform to a specification. 

20  

21 The value can be supplied as a string - e.g. from a config file. 

22 In this case the check will also *convert* the value to 

23 the required type. This allows you to add validation 

24 as a transparent layer to access data stored as strings. 

25 The validation checks that the data is correct *and* 

26 converts it to the expected type. 

27  

28 Some standard checks are provided for basic data types. 

29 Additional checks are easy to write. They can be 

30 provided when the ``Validator`` is instantiated or 

31 added afterwards. 

32  

33 The standard functions work with the following basic data types : 

34  

35 * integers 

36 * floats 

37 * booleans 

38 * strings 

39 * ip_addr 

40  

41 plus lists of these datatypes 

42  

43 Adding additional checks is done through coding simple functions. 

44  

45 The full set of standard checks are :  

46  

47 * 'integer': matches integer values (including negative) 

48 Takes optional 'min' and 'max' arguments : :: 

49  

50 integer() 

51 integer(3, 9) # any value from 3 to 9 

52 integer(min=0) # any positive value 

53 integer(max=9) 

54  

55 * 'float': matches float values 

56 Has the same parameters as the integer check. 

57  

58 * 'boolean': matches boolean values - ``True`` or ``False`` 

59 Acceptable string values for True are : 

60 true, on, yes, 1 

61 Acceptable string values for False are : 

62 false, off, no, 0 

63  

64 Any other value raises an error. 

65  

66 * 'ip_addr': matches an Internet Protocol address, v.4, represented 

67 by a dotted-quad string, i.e. '1.2.3.4'. 

68  

69 * 'string': matches any string. 

70 Takes optional keyword args 'min' and 'max' 

71 to specify min and max lengths of the string. 

72  

73 * 'list': matches any list. 

74 Takes optional keyword args 'min', and 'max' to specify min and 

75 max sizes of the list. (Always returns a list.) 

76  

77 * 'tuple': matches any tuple. 

78 Takes optional keyword args 'min', and 'max' to specify min and 

79 max sizes of the tuple. (Always returns a tuple.) 

80  

81 * 'int_list': Matches a list of integers. 

82 Takes the same arguments as list. 

83  

84 * 'float_list': Matches a list of floats. 

85 Takes the same arguments as list. 

86  

87 * 'bool_list': Matches a list of boolean values. 

88 Takes the same arguments as list. 

89  

90 * 'ip_addr_list': Matches a list of IP addresses. 

91 Takes the same arguments as list. 

92  

93 * 'string_list': Matches a list of strings. 

94 Takes the same arguments as list. 

95  

96 * 'mixed_list': Matches a list with different types in  

97 specific positions. List size must match 

98 the number of arguments. 

99  

100 Each position can be one of : 

101 'integer', 'float', 'ip_addr', 'string', 'boolean' 

102  

103 So to specify a list with two strings followed 

104 by two integers, you write the check as : :: 

105  

106 mixed_list('string', 'string', 'integer', 'integer') 

107  

108 * 'pass': This check matches everything ! It never fails 

109 and the value is unchanged. 

110  

111 It is also the default if no check is specified. 

112  

113 * 'option': This check matches any from a list of options. 

114 You specify this check with : :: 

115  

116 option('option 1', 'option 2', 'option 3') 

117  

118 You can supply a default value (returned if no value is supplied) 

119 using the default keyword argument. 

120  

121 You specify a list argument for default using a list constructor syntax in 

122 the check : :: 

123  

124 checkname(arg1, arg2, default=list('val 1', 'val 2', 'val 3')) 

125  

126 A badly formatted set of arguments will raise a ``VdtParamError``. 

127""" 

128 

129__version__ = '1.0.1' 

130 

131 

132__all__ = ( 

133 '__version__', 

134 'dottedQuadToNum', 

135 'numToDottedQuad', 

136 'ValidateError', 

137 'VdtUnknownCheckError', 

138 'VdtParamError', 

139 'VdtTypeError', 

140 'VdtValueError', 

141 'VdtValueTooSmallError', 

142 'VdtValueTooBigError', 

143 'VdtValueTooShortError', 

144 'VdtValueTooLongError', 

145 'VdtMissingValue', 

146 'Validator', 

147 'is_integer', 

148 'is_float', 

149 'is_boolean', 

150 'is_list', 

151 'is_tuple', 

152 'is_ip_addr', 

153 'is_string', 

154 'is_int_list', 

155 'is_bool_list', 

156 'is_float_list', 

157 'is_string_list', 

158 'is_ip_addr_list', 

159 'is_mixed_list', 

160 'is_option', 

161) 

162 

163 

164import re 

165import sys 

166from pprint import pprint 

167 

168 

169_list_arg = re.compile(r''' 

170 (?: 

171 ([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*list\( 

172 ( 

173 (?: 

174 \s* 

175 (?: 

176 (?:".*?")| # double quotes 

177 (?:'.*?')| # single quotes 

178 (?:[^'",\s\)][^,\)]*?) # unquoted 

179 ) 

180 \s*,\s* 

181 )* 

182 (?: 

183 (?:".*?")| # double quotes 

184 (?:'.*?')| # single quotes 

185 (?:[^'",\s\)][^,\)]*?) # unquoted 

186 )? # last one 

187 ) 

188 \) 

189 ) 

190''', re.VERBOSE | re.DOTALL) # two groups 

191 

192_list_members = re.compile(r''' 

193 ( 

194 (?:".*?")| # double quotes 

195 (?:'.*?')| # single quotes 

196 (?:[^'",\s=][^,=]*?) # unquoted 

197 ) 

198 (?: 

199 (?:\s*,\s*)|(?:\s*$) # comma 

200 ) 

201''', re.VERBOSE | re.DOTALL) # one group 

202 

203_paramstring = r''' 

204 (?: 

205 ( 

206 (?: 

207 [a-zA-Z_][a-zA-Z0-9_]*\s*=\s*list\( 

208 (?: 

209 \s* 

210 (?: 

211 (?:".*?")| # double quotes 

212 (?:'.*?')| # single quotes 

213 (?:[^'",\s\)][^,\)]*?) # unquoted 

214 ) 

215 \s*,\s* 

216 )* 

217 (?: 

218 (?:".*?")| # double quotes 

219 (?:'.*?')| # single quotes 

220 (?:[^'",\s\)][^,\)]*?) # unquoted 

221 )? # last one 

222 \) 

223 )| 

224 (?: 

225 (?:".*?")| # double quotes 

226 (?:'.*?')| # single quotes 

227 (?:[^'",\s=][^,=]*?)| # unquoted 

228 (?: # keyword argument 

229 [a-zA-Z_][a-zA-Z0-9_]*\s*=\s* 

230 (?: 

231 (?:".*?")| # double quotes 

232 (?:'.*?')| # single quotes 

233 (?:[^'",\s=][^,=]*?) # unquoted 

234 ) 

235 ) 

236 ) 

237 ) 

238 (?: 

239 (?:\s*,\s*)|(?:\s*$) # comma 

240 ) 

241 ) 

242 ''' 

243 

244_matchstring = '^%s*' % _paramstring 

245 

246 

247def dottedQuadToNum(ip): 

248 """ 

249 Convert decimal dotted quad string to long integer 

250  

251 >>> int(dottedQuadToNum('1 ')) 

252 1 

253 >>> int(dottedQuadToNum(' 1.2')) 

254 16777218 

255 >>> int(dottedQuadToNum(' 1.2.3 ')) 

256 16908291 

257 >>> int(dottedQuadToNum('1.2.3.4')) 

258 16909060 

259 >>> dottedQuadToNum('255.255.255.255') 

260 4294967295 

261 >>> dottedQuadToNum('255.255.255.256') 

262 Traceback (most recent call last): 

263 ValueError: Not a good dotted-quad IP: 255.255.255.256 

264 """ 

265 

266 # import here to avoid it when ip_addr values are not used 

267 import socket, struct 

268 

269 try: 

270 return struct.unpack('!L', 

271 socket.inet_aton(ip.strip()))[0] 

272 except socket.error: 

273 raise ValueError('Not a good dotted-quad IP: %s' % ip) 

274 return 

275 

276 

277def numToDottedQuad(num): 

278 """ 

279 Convert int or long int to dotted quad string 

280  

281 >>> numToDottedQuad(int(-1)) 

282 Traceback (most recent call last): 

283 ValueError: Not a good numeric IP: -1 

284 >>> numToDottedQuad(int(1)) 

285 '0.0.0.1' 

286 >>> numToDottedQuad(int(16777218)) 

287 '1.0.0.2' 

288 >>> numToDottedQuad(int(16908291)) 

289 '1.2.0.3' 

290 >>> numToDottedQuad(int(16909060)) 

291 '1.2.3.4' 

292 >>> numToDottedQuad(int(4294967295)) 

293 '255.255.255.255' 

294 >>> numToDottedQuad(int(4294967296)) 

295 Traceback (most recent call last): 

296 ValueError: Not a good numeric IP: 4294967296 

297 >>> numToDottedQuad(-1) 

298 Traceback (most recent call last): 

299 ValueError: Not a good numeric IP: -1 

300 >>> numToDottedQuad(1) 

301 '0.0.0.1' 

302 >>> numToDottedQuad(16777218) 

303 '1.0.0.2' 

304 >>> numToDottedQuad(16908291) 

305 '1.2.0.3' 

306 >>> numToDottedQuad(16909060) 

307 '1.2.3.4' 

308 >>> numToDottedQuad(4294967295) 

309 '255.255.255.255' 

310 >>> numToDottedQuad(4294967296) 

311 Traceback (most recent call last): 

312 ValueError: Not a good numeric IP: 4294967296 

313 

314 """ 

315 

316 # import here to avoid it when ip_addr values are not used 

317 import socket, struct 

318 

319 # no need to intercept here, 4294967295L is fine 

320 if num > int(4294967295) or num < 0: 

321 raise ValueError('Not a good numeric IP: %s' % num) 

322 try: 

323 return socket.inet_ntoa( 

324 struct.pack('!L', int(num))) 

325 except (socket.error, struct.error, OverflowError): 

326 raise ValueError('Not a good numeric IP: %s' % num) 

327 

328 

329class ValidateError(Exception): 

330 """ 

331 This error indicates that the check failed. 

332 It can be the base class for more specific errors. 

333  

334 Any check function that fails ought to raise this error. 

335 (or a subclass) 

336  

337 >>> raise ValidateError 

338 Traceback (most recent call last): 

339 ValidateError 

340 """ 

341 

342 

343class VdtMissingValue(ValidateError): 

344 """No value was supplied to a check that needed one.""" 

345 

346 

347class VdtUnknownCheckError(ValidateError): 

348 """An unknown check function was requested""" 

349 

350 def __init__(self, value): 

351 """ 

352 >>> raise VdtUnknownCheckError('yoda') 

353 Traceback (most recent call last): 

354 VdtUnknownCheckError: the check "yoda" is unknown. 

355 """ 

356 ValidateError.__init__(self, 'the check "%s" is unknown.' % (value,)) 

357 

358 

359class VdtParamError(SyntaxError): 

360 """An incorrect parameter was passed""" 

361 

362 def __init__(self, name, value): 

363 """ 

364 >>> raise VdtParamError('yoda', 'jedi') 

365 Traceback (most recent call last): 

366 VdtParamError: passed an incorrect value "jedi" for parameter "yoda". 

367 """ 

368 SyntaxError.__init__(self, 'passed an incorrect value "%s" for parameter "%s".' % (value, name)) 

369 

370 

371class VdtTypeError(ValidateError): 

372 """The value supplied was of the wrong type""" 

373 

374 def __init__(self, value): 

375 """ 

376 >>> raise VdtTypeError('jedi') 

377 Traceback (most recent call last): 

378 VdtTypeError: the value "jedi" is of the wrong type. 

379 """ 

380 ValidateError.__init__(self, 'the value "%s" is of the wrong type.' % (value,)) 

381 

382 

383class VdtValueError(ValidateError): 

384 """The value supplied was of the correct type, but was not an allowed value.""" 

385 

386 def __init__(self, value): 

387 """ 

388 >>> raise VdtValueError('jedi') 

389 Traceback (most recent call last): 

390 VdtValueError: the value "jedi" is unacceptable. 

391 """ 

392 ValidateError.__init__(self, 'the value "%s" is unacceptable.' % (value,)) 

393 

394 

395class VdtValueTooSmallError(VdtValueError): 

396 """The value supplied was of the correct type, but was too small.""" 

397 

398 def __init__(self, value): 

399 """ 

400 >>> raise VdtValueTooSmallError('0') 

401 Traceback (most recent call last): 

402 VdtValueTooSmallError: the value "0" is too small. 

403 """ 

404 ValidateError.__init__(self, 'the value "%s" is too small.' % (value,)) 1d

405 

406 

407class VdtValueTooBigError(VdtValueError): 

408 """The value supplied was of the correct type, but was too big.""" 

409 

410 def __init__(self, value): 

411 """ 

412 >>> raise VdtValueTooBigError('1') 

413 Traceback (most recent call last): 

414 VdtValueTooBigError: the value "1" is too big. 

415 """ 

416 ValidateError.__init__(self, 'the value "%s" is too big.' % (value,)) 

417 

418 

419class VdtValueTooShortError(VdtValueError): 

420 """The value supplied was of the correct type, but was too short.""" 

421 

422 def __init__(self, value): 

423 """ 

424 >>> raise VdtValueTooShortError('jed') 

425 Traceback (most recent call last): 

426 VdtValueTooShortError: the value "jed" is too short. 

427 """ 

428 ValidateError.__init__( 

429 self, 

430 'the value "%s" is too short.' % (value,)) 

431 

432 

433class VdtValueTooLongError(VdtValueError): 

434 """The value supplied was of the correct type, but was too long.""" 

435 

436 def __init__(self, value): 

437 """ 

438 >>> raise VdtValueTooLongError('jedie') 

439 Traceback (most recent call last): 

440 VdtValueTooLongError: the value "jedie" is too long. 

441 """ 

442 ValidateError.__init__(self, 'the value "%s" is too long.' % (value,)) 

443 

444 

445class Validator(object): 

446 """ 

447 Validator is an object that allows you to register a set of 'checks'. 

448 These checks take input and test that it conforms to the check. 

449  

450 This can also involve converting the value from a string into 

451 the correct datatype. 

452  

453 The ``check`` method takes an input string which configures which 

454 check is to be used and applies that check to a supplied value. 

455  

456 An example input string would be: 

457 'int_range(param1, param2)' 

458  

459 You would then provide something like: 

460  

461 >>> def int_range_check(value, min, max): 

462 ... # turn min and max from strings to integers 

463 ... min = int(min) 

464 ... max = int(max) 

465 ... # check that value is of the correct type. 

466 ... # possible valid inputs are integers or strings 

467 ... # that represent integers 

468 ... if not isinstance(value, (int, str)): 

469 ... raise VdtTypeError(value) 

470 ... elif isinstance(value, str): 

471 ... # if we are given a string 

472 ... # attempt to convert to an integer 

473 ... try: 

474 ... value = int(value) 

475 ... except ValueError: 

476 ... raise VdtValueError(value) 

477 ... # check the value is between our constraints 

478 ... if not min <= value: 

479 ... raise VdtValueTooSmallError(value) 

480 ... if not value <= max: 

481 ... raise VdtValueTooBigError(value) 

482 ... return value 

483  

484 >>> fdict = {'int_range': int_range_check} 

485 >>> vtr1 = Validator(fdict) 

486 >>> vtr1.check('int_range(20, 40)', '30') 

487 30 

488 >>> vtr1.check('int_range(20, 40)', '60') 

489 Traceback (most recent call last): 

490 VdtValueTooBigError: the value "60" is too big. 

491  

492 New functions can be added with : :: 

493  

494 >>> vtr2 = Validator()  

495 >>> vtr2.functions['int_range'] = int_range_check 

496  

497 Or by passing in a dictionary of functions when Validator  

498 is instantiated. 

499  

500 Your functions *can* use keyword arguments, 

501 but the first argument should always be 'value'. 

502  

503 If the function doesn't take additional arguments, 

504 the parentheses are optional in the check. 

505 It can be written with either of : :: 

506  

507 keyword = function_name 

508 keyword = function_name() 

509  

510 The first program to utilise Validator() was Michael Foord's 

511 ConfigObj, an alternative to ConfigParser which supports lists and 

512 can validate a config file using a config schema. 

513 For more details on using Validator with ConfigObj see: 

514 https://configobj.readthedocs.org/en/latest/configobj.html 

515 """ 

516 

517 # this regex does the initial parsing of the checks 

518 _func_re = re.compile(r'([^\(\)]+?)\((.*)\)', re.DOTALL) 

519 

520 # this regex takes apart keyword arguments 

521 _key_arg = re.compile(r'^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.*)$', re.DOTALL) 

522 

523 

524 # this regex finds keyword=list(....) type values 

525 _list_arg = _list_arg 

526 

527 # this regex takes individual values out of lists - in one pass 

528 _list_members = _list_members 

529 

530 # These regexes check a set of arguments for validity 

531 # and then pull the members out 

532 _paramfinder = re.compile(_paramstring, re.VERBOSE | re.DOTALL) 

533 _matchfinder = re.compile(_matchstring, re.VERBOSE | re.DOTALL) 

534 

535 

536 def __init__(self, functions=None): 

537 """ 

538 >>> vtri = Validator() 

539 """ 

540 self.functions = { 1cb

541 '': self._pass, 

542 'integer': is_integer, 

543 'float': is_float, 

544 'boolean': is_boolean, 

545 'ip_addr': is_ip_addr, 

546 'string': is_string, 

547 'list': is_list, 

548 'tuple': is_tuple, 

549 'int_list': is_int_list, 

550 'float_list': is_float_list, 

551 'bool_list': is_bool_list, 

552 'ip_addr_list': is_ip_addr_list, 

553 'string_list': is_string_list, 

554 'mixed_list': is_mixed_list, 

555 'pass': self._pass, 

556 'option': is_option, 

557 'force_list': force_list, 

558 } 

559 if functions is not None: 559 ↛ 560line 559 didn't jump to line 560 because the condition on line 559 was never true1cb

560 self.functions.update(functions) 

561 # tekNico: for use by ConfigObj 

562 self.baseErrorClass = ValidateError 1cb

563 self._cache = {} 1cb

564 

565 

566 def check(self, check, value, missing=False): 

567 """ 

568 Usage: check(check, value) 

569  

570 Arguments: 

571 check: string representing check to apply (including arguments) 

572 value: object to be checked 

573 Returns value, converted to correct type if necessary 

574  

575 If the check fails, raises a ``ValidateError`` subclass. 

576  

577 >>> vtor.check('yoda', '') 

578 Traceback (most recent call last): 

579 VdtUnknownCheckError: the check "yoda" is unknown. 

580 >>> vtor.check('yoda()', '') 

581 Traceback (most recent call last): 

582 VdtUnknownCheckError: the check "yoda" is unknown. 

583  

584 >>> vtor.check('string(default="")', '', missing=True) 

585 '' 

586 """ 

587 fun_name, fun_args, fun_kwargs, default = self._parse_with_caching(check) 1bad

588 

589 if missing: 1bad

590 if default is None: 590 ↛ 592line 590 didn't jump to line 592 because the condition on line 590 was never true1a

591 # no information needed here - to be handled by caller 

592 raise VdtMissingValue() 

593 value = self._handle_none(default) 1a

594 

595 if value is None: 595 ↛ 596line 595 didn't jump to line 596 because the condition on line 595 was never true1bad

596 return None 

597 

598 return self._check_value(value, fun_name, fun_args, fun_kwargs) 1bad

599 

600 

601 def _handle_none(self, value): 

602 if value == 'None': 602 ↛ 603line 602 didn't jump to line 603 because the condition on line 602 was never true1a

603 return None 

604 elif value in ("'None'", '"None"'): 604 ↛ 606line 604 didn't jump to line 606 because the condition on line 604 was never true1a

605 # Special case a quoted None 

606 value = self._unquote(value) 

607 return value 1a

608 

609 

610 def _parse_with_caching(self, check): 

611 if check in self._cache: 1bad

612 fun_name, fun_args, fun_kwargs, default = self._cache[check] 1bad

613 # We call list and dict below to work with *copies* of the data 

614 # rather than the original (which are mutable of course) 

615 fun_args = list(fun_args) 1bad

616 fun_kwargs = dict(fun_kwargs) 1bad

617 else: 

618 fun_name, fun_args, fun_kwargs, default = self._parse_check(check) 1bad

619 fun_kwargs = dict([(str(key), value) for (key, value) in list(fun_kwargs.items())]) 1bad

620 self._cache[check] = fun_name, list(fun_args), dict(fun_kwargs), default 1bad

621 return fun_name, fun_args, fun_kwargs, default 1bad

622 

623 

624 def _check_value(self, value, fun_name, fun_args, fun_kwargs): 

625 try: 1bad

626 fun = self.functions[fun_name] 1bad

627 except KeyError: 

628 raise VdtUnknownCheckError(fun_name) 

629 else: 

630 return fun(value, *fun_args, **fun_kwargs) 1bad

631 

632 

633 def _parse_check(self, check): 

634 fun_match = self._func_re.match(check) 1bad

635 if fun_match: 1bad

636 fun_name = fun_match.group(1) 1bad

637 arg_string = fun_match.group(2) 1bad

638 arg_match = self._matchfinder.match(arg_string) 1bad

639 if arg_match is None: 639 ↛ 641line 639 didn't jump to line 641 because the condition on line 639 was never true1bad

640 # Bad syntax 

641 raise VdtParamError('Bad syntax in check "%s".' % check) 

642 fun_args = [] 1bad

643 fun_kwargs = {} 1bad

644 # pull out args of group 2 

645 for arg in self._paramfinder.findall(arg_string): 1bad

646 # args may need whitespace removing (before removing quotes) 

647 arg = arg.strip() 1bad

648 listmatch = self._list_arg.match(arg) 1bad

649 if listmatch: 649 ↛ 650line 649 didn't jump to line 650 because the condition on line 649 was never true1bad

650 key, val = self._list_handle(listmatch) 

651 fun_kwargs[key] = val 

652 continue 

653 keymatch = self._key_arg.match(arg) 1bad

654 if keymatch: 1bad

655 val = keymatch.group(2) 1a

656 if not val in ("'None'", '"None"'): 656 ↛ 659line 656 didn't jump to line 659 because the condition on line 656 was always true1a

657 # Special case a quoted None 

658 val = self._unquote(val) 1a

659 fun_kwargs[keymatch.group(1)] = val 1a

660 continue 1a

661 

662 fun_args.append(self._unquote(arg)) 1bd

663 else: 

664 # allows for function names without (args) 

665 return check, (), {}, None 1bd

666 

667 # Default must be deleted if the value is specified too, 

668 # otherwise the check function will get a spurious "default" keyword arg 

669 default = fun_kwargs.pop('default', None) 1bad

670 return fun_name, fun_args, fun_kwargs, default 1bad

671 

672 

673 def _unquote(self, val): 

674 """Unquote a value if necessary.""" 

675 if (len(val) >= 2) and (val[0] in ("'", '"')) and (val[0] == val[-1]): 675 ↛ 676line 675 didn't jump to line 676 because the condition on line 675 was never true1bad

676 val = val[1:-1] 

677 return val 1bad

678 

679 

680 def _list_handle(self, listmatch): 

681 """Take apart a ``keyword=list('val, 'val')`` type string.""" 

682 out = [] 

683 name = listmatch.group(1) 

684 args = listmatch.group(2) 

685 for arg in self._list_members.findall(args): 

686 out.append(self._unquote(arg)) 

687 return name, out 

688 

689 

690 def _pass(self, value): 

691 """ 

692 Dummy check that always passes 

693  

694 >>> vtor.check('', 0) 

695 0 

696 >>> vtor.check('', '0') 

697 '0' 

698 """ 

699 return value 

700 

701 

702 def get_default_value(self, check): 

703 """ 

704 Given a check, return the default value for the check 

705 (converted to the right type). 

706  

707 If the check doesn't specify a default value then a 

708 ``KeyError`` will be raised. 

709 """ 

710 fun_name, fun_args, fun_kwargs, default = self._parse_with_caching(check) 1bad

711 if default is None: 1bad

712 raise KeyError('Check "%s" has no default value.' % check) 1bd

713 value = self._handle_none(default) 1a

714 if value is None: 714 ↛ 715line 714 didn't jump to line 715 because the condition on line 714 was never true1a

715 return value 

716 return self._check_value(value, fun_name, fun_args, fun_kwargs) 1a

717 

718 

719def _is_num_param(names, values, to_float=False): 

720 """ 

721 Return numbers from inputs or raise VdtParamError. 

722  

723 Lets ``None`` pass through. 

724 Pass in keyword argument ``to_float=True`` to 

725 use float for the conversion rather than int. 

726  

727 >>> _is_num_param(('', ''), (0, 1.0)) 

728 [0, 1] 

729 >>> _is_num_param(('', ''), (0, 1.0), to_float=True) 

730 [0.0, 1.0] 

731 >>> _is_num_param(('a'), ('a')) 

732 Traceback (most recent call last): 

733 VdtParamError: passed an incorrect value "a" for parameter "a". 

734 """ 

735 fun = to_float and float or int 1bad

736 out_params = [] 1bad

737 for (name, val) in zip(names, values): 1bad

738 if val is None: 1bad

739 out_params.append(val) 1bad

740 elif isinstance(val, (int, float, str)): 740 ↛ 746line 740 didn't jump to line 746 because the condition on line 740 was always true1bd

741 try: 1bd

742 out_params.append(fun(val)) 1bd

743 except ValueError as e: 

744 raise VdtParamError(name, val) 

745 else: 

746 raise VdtParamError(name, val) 

747 return out_params 1bad

748 

749 

750# built in checks 

751# you can override these by setting the appropriate name 

752# in Validator.functions 

753# note: if the params are specified wrongly in your input string, 

754# you will also raise errors. 

755 

756def is_integer(value, min=None, max=None): 

757 """ 

758 A check that tests that a given value is an integer (int) 

759 and optionally, between bounds. A negative value is accepted, while 

760 a float will fail. 

761  

762 If the value is a string, then the conversion is done - if possible. 

763 Otherwise a VdtError is raised. 

764  

765 >>> vtor.check('integer', '-1') 

766 -1 

767 >>> vtor.check('integer', '0') 

768 0 

769 >>> vtor.check('integer', 9) 

770 9 

771 >>> vtor.check('integer', 'a') 

772 Traceback (most recent call last): 

773 VdtTypeError: the value "a" is of the wrong type. 

774 >>> vtor.check('integer', '2.2') 

775 Traceback (most recent call last): 

776 VdtTypeError: the value "2.2" is of the wrong type. 

777 >>> vtor.check('integer(10)', '20') 

778 20 

779 >>> vtor.check('integer(max=20)', '15') 

780 15 

781 >>> vtor.check('integer(10)', '9') 

782 Traceback (most recent call last): 

783 VdtValueTooSmallError: the value "9" is too small. 

784 >>> vtor.check('integer(10)', 9) 

785 Traceback (most recent call last): 

786 VdtValueTooSmallError: the value "9" is too small. 

787 >>> vtor.check('integer(max=20)', '35') 

788 Traceback (most recent call last): 

789 VdtValueTooBigError: the value "35" is too big. 

790 >>> vtor.check('integer(max=20)', 35) 

791 Traceback (most recent call last): 

792 VdtValueTooBigError: the value "35" is too big. 

793 >>> vtor.check('integer(0, 9)', False) 

794 0 

795 """ 

796 (min_val, max_val) = _is_num_param(('min', 'max'), (min, max)) 1bad

797 if not isinstance(value, (int, str)): 797 ↛ 798line 797 didn't jump to line 798 because the condition on line 797 was never true1bad

798 raise VdtTypeError(value) 

799 if isinstance(value, str): 1bad

800 # if it's a string - does it represent an integer ? 

801 try: 1bad

802 value = int(value) 1bad

803 except ValueError: 

804 raise VdtTypeError(value) 

805 if (min_val is not None) and (value < min_val): 805 ↛ 806line 805 didn't jump to line 806 because the condition on line 805 was never true1bad

806 raise VdtValueTooSmallError(value) 

807 if (max_val is not None) and (value > max_val): 807 ↛ 808line 807 didn't jump to line 808 because the condition on line 807 was never true1bad

808 raise VdtValueTooBigError(value) 

809 return value 1bad

810 

811 

812def is_float(value, min=None, max=None): 

813 """ 

814 A check that tests that a given value is a float 

815 (an integer will be accepted), and optionally - that it is between bounds. 

816  

817 If the value is a string, then the conversion is done - if possible. 

818 Otherwise a VdtError is raised. 

819  

820 This can accept negative values. 

821  

822 >>> vtor.check('float', '2') 

823 2.0 

824  

825 From now on we multiply the value to avoid comparing decimals 

826  

827 >>> vtor.check('float', '-6.8') * 10 

828 -68.0 

829 >>> vtor.check('float', '12.2') * 10 

830 122.0 

831 >>> vtor.check('float', 8.4) * 10 

832 84.0 

833 >>> vtor.check('float', 'a') 

834 Traceback (most recent call last): 

835 VdtTypeError: the value "a" is of the wrong type. 

836 >>> vtor.check('float(10.1)', '10.2') * 10 

837 102.0 

838 >>> vtor.check('float(max=20.2)', '15.1') * 10 

839 151.0 

840 >>> vtor.check('float(10.0)', '9.0') 

841 Traceback (most recent call last): 

842 VdtValueTooSmallError: the value "9.0" is too small. 

843 >>> vtor.check('float(max=20.0)', '35.0') 

844 Traceback (most recent call last): 

845 VdtValueTooBigError: the value "35.0" is too big. 

846 """ 

847 (min_val, max_val) = _is_num_param( 1bad

848 ('min', 'max'), (min, max), to_float=True) 

849 if not isinstance(value, (int, float, str)): 849 ↛ 850line 849 didn't jump to line 850 because the condition on line 849 was never true1bad

850 raise VdtTypeError(value) 

851 if not isinstance(value, float): 851 ↛ 857line 851 didn't jump to line 857 because the condition on line 851 was always true1bad

852 # if it's a string - does it represent a float ? 

853 try: 1bad

854 value = float(value) 1bad

855 except ValueError: 

856 raise VdtTypeError(value) 

857 if (min_val is not None) and (value < min_val): 1bad

858 raise VdtValueTooSmallError(value) 1d

859 if (max_val is not None) and (value > max_val): 859 ↛ 860line 859 didn't jump to line 860 because the condition on line 859 was never true1ba

860 raise VdtValueTooBigError(value) 

861 return value 1ba

862 

863 

864bool_dict = { 

865 True: True, 'on': True, '1': True, 'true': True, 'yes': True, 

866 False: False, 'off': False, '0': False, 'false': False, 'no': False, 

867} 

868 

869 

870def is_boolean(value): 

871 """ 

872 Check if the value represents a boolean. 

873  

874 >>> vtor.check('boolean', 0) 

875 0 

876 >>> vtor.check('boolean', False) 

877 0 

878 >>> vtor.check('boolean', '0') 

879 0 

880 >>> vtor.check('boolean', 'off') 

881 0 

882 >>> vtor.check('boolean', 'false') 

883 0 

884 >>> vtor.check('boolean', 'no') 

885 0 

886 >>> vtor.check('boolean', 'nO') 

887 0 

888 >>> vtor.check('boolean', 'NO') 

889 0 

890 >>> vtor.check('boolean', 1) 

891 1 

892 >>> vtor.check('boolean', True) 

893 1 

894 >>> vtor.check('boolean', '1') 

895 1 

896 >>> vtor.check('boolean', 'on') 

897 1 

898 >>> vtor.check('boolean', 'true') 

899 1 

900 >>> vtor.check('boolean', 'yes') 

901 1 

902 >>> vtor.check('boolean', 'Yes') 

903 1 

904 >>> vtor.check('boolean', 'YES') 

905 1 

906 >>> vtor.check('boolean', '') 

907 Traceback (most recent call last): 

908 VdtTypeError: the value "" is of the wrong type. 

909 >>> vtor.check('boolean', 'up') 

910 Traceback (most recent call last): 

911 VdtTypeError: the value "up" is of the wrong type. 

912  

913 """ 

914 if isinstance(value, str): 914 ↛ 922line 914 didn't jump to line 922 because the condition on line 914 was always true1a

915 try: 1a

916 return bool_dict[value.lower()] 1a

917 except KeyError: 

918 raise VdtTypeError(value) 

919 # we do an equality test rather than an identity test 

920 # this ensures Python 2.2 compatibilty 

921 # and allows 0 and 1 to represent True and False 

922 if value == False: 

923 return False 

924 elif value == True: 

925 return True 

926 else: 

927 raise VdtTypeError(value) 

928 

929 

930def is_ip_addr(value): 

931 """ 

932 Check that the supplied value is an Internet Protocol address, v.4, 

933 represented by a dotted-quad string, i.e. '1.2.3.4'. 

934  

935 >>> vtor.check('ip_addr', '1 ') 

936 '1' 

937 >>> vtor.check('ip_addr', ' 1.2') 

938 '1.2' 

939 >>> vtor.check('ip_addr', ' 1.2.3 ') 

940 '1.2.3' 

941 >>> vtor.check('ip_addr', '1.2.3.4') 

942 '1.2.3.4' 

943 >>> vtor.check('ip_addr', '0.0.0.0') 

944 '0.0.0.0' 

945 >>> vtor.check('ip_addr', '255.255.255.255') 

946 '255.255.255.255' 

947 >>> vtor.check('ip_addr', '255.255.255.256') 

948 Traceback (most recent call last): 

949 VdtValueError: the value "255.255.255.256" is unacceptable. 

950 >>> vtor.check('ip_addr', '1.2.3.4.5') 

951 Traceback (most recent call last): 

952 VdtValueError: the value "1.2.3.4.5" is unacceptable. 

953 >>> vtor.check('ip_addr', 0) 

954 Traceback (most recent call last): 

955 VdtTypeError: the value "0" is of the wrong type. 

956 """ 

957 if not isinstance(value, str): 

958 raise VdtTypeError(value) 

959 value = value.strip() 

960 try: 

961 dottedQuadToNum(value) 

962 except ValueError: 

963 raise VdtValueError(value) 

964 return value 

965 

966 

967def is_list(value, min=None, max=None): 

968 """ 

969 Check that the value is a list of values. 

970  

971 You can optionally specify the minimum and maximum number of members. 

972  

973 It does no check on list members. 

974  

975 >>> vtor.check('list', ()) 

976 [] 

977 >>> vtor.check('list', []) 

978 [] 

979 >>> vtor.check('list', (1, 2)) 

980 [1, 2] 

981 >>> vtor.check('list', [1, 2]) 

982 [1, 2] 

983 >>> vtor.check('list(3)', (1, 2)) 

984 Traceback (most recent call last): 

985 VdtValueTooShortError: the value "(1, 2)" is too short. 

986 >>> vtor.check('list(max=5)', (1, 2, 3, 4, 5, 6)) 

987 Traceback (most recent call last): 

988 VdtValueTooLongError: the value "(1, 2, 3, 4, 5, 6)" is too long. 

989 >>> vtor.check('list(min=3, max=5)', (1, 2, 3, 4)) 

990 [1, 2, 3, 4] 

991 >>> vtor.check('list', 0) 

992 Traceback (most recent call last): 

993 VdtTypeError: the value "0" is of the wrong type. 

994 >>> vtor.check('list', '12') 

995 Traceback (most recent call last): 

996 VdtTypeError: the value "12" is of the wrong type. 

997 """ 

998 (min_len, max_len) = _is_num_param(('min', 'max'), (min, max)) 

999 if isinstance(value, str): 

1000 raise VdtTypeError(value) 

1001 try: 

1002 num_members = len(value) 

1003 except TypeError: 

1004 raise VdtTypeError(value) 

1005 if min_len is not None and num_members < min_len: 

1006 raise VdtValueTooShortError(value) 

1007 if max_len is not None and num_members > max_len: 

1008 raise VdtValueTooLongError(value) 

1009 return list(value) 

1010 

1011 

1012def is_tuple(value, min=None, max=None): 

1013 """ 

1014 Check that the value is a tuple of values. 

1015  

1016 You can optionally specify the minimum and maximum number of members. 

1017  

1018 It does no check on members. 

1019  

1020 >>> vtor.check('tuple', ()) 

1021 () 

1022 >>> vtor.check('tuple', []) 

1023 () 

1024 >>> vtor.check('tuple', (1, 2)) 

1025 (1, 2) 

1026 >>> vtor.check('tuple', [1, 2]) 

1027 (1, 2) 

1028 >>> vtor.check('tuple(3)', (1, 2)) 

1029 Traceback (most recent call last): 

1030 VdtValueTooShortError: the value "(1, 2)" is too short. 

1031 >>> vtor.check('tuple(max=5)', (1, 2, 3, 4, 5, 6)) 

1032 Traceback (most recent call last): 

1033 VdtValueTooLongError: the value "(1, 2, 3, 4, 5, 6)" is too long. 

1034 >>> vtor.check('tuple(min=3, max=5)', (1, 2, 3, 4)) 

1035 (1, 2, 3, 4) 

1036 >>> vtor.check('tuple', 0) 

1037 Traceback (most recent call last): 

1038 VdtTypeError: the value "0" is of the wrong type. 

1039 >>> vtor.check('tuple', '12') 

1040 Traceback (most recent call last): 

1041 VdtTypeError: the value "12" is of the wrong type. 

1042 """ 

1043 return tuple(is_list(value, min, max)) 

1044 

1045 

1046def is_string(value, min=None, max=None): 

1047 """ 

1048 Check that the supplied value is a string. 

1049  

1050 You can optionally specify the minimum and maximum number of members. 

1051  

1052 >>> vtor.check('string', '0') 

1053 '0' 

1054 >>> vtor.check('string', 0) 

1055 Traceback (most recent call last): 

1056 VdtTypeError: the value "0" is of the wrong type. 

1057 >>> vtor.check('string(2)', '12') 

1058 '12' 

1059 >>> vtor.check('string(2)', '1') 

1060 Traceback (most recent call last): 

1061 VdtValueTooShortError: the value "1" is too short. 

1062 >>> vtor.check('string(min=2, max=3)', '123') 

1063 '123' 

1064 >>> vtor.check('string(min=2, max=3)', '1234') 

1065 Traceback (most recent call last): 

1066 VdtValueTooLongError: the value "1234" is too long. 

1067 """ 

1068 if not isinstance(value, str): 1068 ↛ 1069line 1068 didn't jump to line 1069 because the condition on line 1068 was never true1bad

1069 raise VdtTypeError(value) 

1070 (min_len, max_len) = _is_num_param(('min', 'max'), (min, max)) 1bad

1071 try: 1bad

1072 num_members = len(value) 1bad

1073 except TypeError: 

1074 raise VdtTypeError(value) 

1075 if min_len is not None and num_members < min_len: 1075 ↛ 1076line 1075 didn't jump to line 1076 because the condition on line 1075 was never true1bad

1076 raise VdtValueTooShortError(value) 

1077 if max_len is not None and num_members > max_len: 1077 ↛ 1078line 1077 didn't jump to line 1078 because the condition on line 1077 was never true1bad

1078 raise VdtValueTooLongError(value) 

1079 return value 1bad

1080 

1081 

1082def is_int_list(value, min=None, max=None): 

1083 """ 

1084 Check that the value is a list of integers. 

1085  

1086 You can optionally specify the minimum and maximum number of members. 

1087  

1088 Each list member is checked that it is an integer. 

1089  

1090 >>> vtor.check('int_list', ()) 

1091 [] 

1092 >>> vtor.check('int_list', []) 

1093 [] 

1094 >>> vtor.check('int_list', (1, 2)) 

1095 [1, 2] 

1096 >>> vtor.check('int_list', [1, 2]) 

1097 [1, 2] 

1098 >>> vtor.check('int_list', [1, 'a']) 

1099 Traceback (most recent call last): 

1100 VdtTypeError: the value "a" is of the wrong type. 

1101 """ 

1102 return [is_integer(mem) for mem in is_list(value, min, max)] 

1103 

1104 

1105def is_bool_list(value, min=None, max=None): 

1106 """ 

1107 Check that the value is a list of booleans. 

1108  

1109 You can optionally specify the minimum and maximum number of members. 

1110  

1111 Each list member is checked that it is a boolean. 

1112  

1113 >>> vtor.check('bool_list', ()) 

1114 [] 

1115 >>> vtor.check('bool_list', []) 

1116 [] 

1117 >>> check_res = vtor.check('bool_list', (True, False)) 

1118 >>> check_res == [True, False] 

1119 1 

1120 >>> check_res = vtor.check('bool_list', [True, False]) 

1121 >>> check_res == [True, False] 

1122 1 

1123 >>> vtor.check('bool_list', [True, 'a']) 

1124 Traceback (most recent call last): 

1125 VdtTypeError: the value "a" is of the wrong type. 

1126 """ 

1127 return [is_boolean(mem) for mem in is_list(value, min, max)] 

1128 

1129 

1130def is_float_list(value, min=None, max=None): 

1131 """ 

1132 Check that the value is a list of floats. 

1133  

1134 You can optionally specify the minimum and maximum number of members. 

1135  

1136 Each list member is checked that it is a float. 

1137  

1138 >>> vtor.check('float_list', ()) 

1139 [] 

1140 >>> vtor.check('float_list', []) 

1141 [] 

1142 >>> vtor.check('float_list', (1, 2.0)) 

1143 [1.0, 2.0] 

1144 >>> vtor.check('float_list', [1, 2.0]) 

1145 [1.0, 2.0] 

1146 >>> vtor.check('float_list', [1, 'a']) 

1147 Traceback (most recent call last): 

1148 VdtTypeError: the value "a" is of the wrong type. 

1149 """ 

1150 return [is_float(mem) for mem in is_list(value, min, max)] 

1151 

1152 

1153def is_string_list(value, min=None, max=None): 

1154 """ 

1155 Check that the value is a list of strings. 

1156  

1157 You can optionally specify the minimum and maximum number of members. 

1158  

1159 Each list member is checked that it is a string. 

1160  

1161 >>> vtor.check('string_list', ()) 

1162 [] 

1163 >>> vtor.check('string_list', []) 

1164 [] 

1165 >>> vtor.check('string_list', ('a', 'b')) 

1166 ['a', 'b'] 

1167 >>> vtor.check('string_list', ['a', 1]) 

1168 Traceback (most recent call last): 

1169 VdtTypeError: the value "1" is of the wrong type. 

1170 >>> vtor.check('string_list', 'hello') 

1171 Traceback (most recent call last): 

1172 VdtTypeError: the value "hello" is of the wrong type. 

1173 """ 

1174 if isinstance(value, str): 

1175 raise VdtTypeError(value) 

1176 return [is_string(mem) for mem in is_list(value, min, max)] 

1177 

1178 

1179def is_ip_addr_list(value, min=None, max=None): 

1180 """ 

1181 Check that the value is a list of IP addresses. 

1182  

1183 You can optionally specify the minimum and maximum number of members. 

1184  

1185 Each list member is checked that it is an IP address. 

1186  

1187 >>> vtor.check('ip_addr_list', ()) 

1188 [] 

1189 >>> vtor.check('ip_addr_list', []) 

1190 [] 

1191 >>> vtor.check('ip_addr_list', ('1.2.3.4', '5.6.7.8')) 

1192 ['1.2.3.4', '5.6.7.8'] 

1193 >>> vtor.check('ip_addr_list', ['a']) 

1194 Traceback (most recent call last): 

1195 VdtValueError: the value "a" is unacceptable. 

1196 """ 

1197 return [is_ip_addr(mem) for mem in is_list(value, min, max)] 

1198 

1199 

1200def force_list(value, min=None, max=None): 

1201 """ 

1202 Check that a value is a list, coercing strings into 

1203 a list with one member. Useful where users forget the 

1204 trailing comma that turns a single value into a list. 

1205  

1206 You can optionally specify the minimum and maximum number of members. 

1207 A minumum of greater than one will fail if the user only supplies a 

1208 string. 

1209  

1210 >>> vtor.check('force_list', ()) 

1211 [] 

1212 >>> vtor.check('force_list', []) 

1213 [] 

1214 >>> vtor.check('force_list', 'hello') 

1215 ['hello'] 

1216 """ 

1217 if not isinstance(value, (list, tuple)): 

1218 value = [value] 

1219 return is_list(value, min, max) 

1220 

1221 

1222 

1223fun_dict = { 

1224 'integer': is_integer, 

1225 'float': is_float, 

1226 'ip_addr': is_ip_addr, 

1227 'string': is_string, 

1228 'boolean': is_boolean, 

1229} 

1230 

1231 

1232def is_mixed_list(value, *args): 

1233 """ 

1234 Check that the value is a list. 

1235 Allow specifying the type of each member. 

1236 Work on lists of specific lengths. 

1237  

1238 You specify each member as a positional argument specifying type 

1239  

1240 Each type should be one of the following strings : 

1241 'integer', 'float', 'ip_addr', 'string', 'boolean' 

1242  

1243 So you can specify a list of two strings, followed by 

1244 two integers as : 

1245  

1246 mixed_list('string', 'string', 'integer', 'integer') 

1247  

1248 The length of the list must match the number of positional 

1249 arguments you supply. 

1250  

1251 >>> mix_str = "mixed_list('integer', 'float', 'ip_addr', 'string', 'boolean')" 

1252 >>> check_res = vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', True)) 

1253 >>> check_res == [1, 2.0, '1.2.3.4', 'a', True] 

1254 1 

1255 >>> check_res = vtor.check(mix_str, ('1', '2.0', '1.2.3.4', 'a', 'True')) 

1256 >>> check_res == [1, 2.0, '1.2.3.4', 'a', True] 

1257 1 

1258 >>> vtor.check(mix_str, ('b', 2.0, '1.2.3.4', 'a', True)) 

1259 Traceback (most recent call last): 

1260 VdtTypeError: the value "b" is of the wrong type. 

1261 >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a')) 

1262 Traceback (most recent call last): 

1263 VdtValueTooShortError: the value "(1, 2.0, '1.2.3.4', 'a')" is too short. 

1264 >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', 1, 'b')) 

1265 Traceback (most recent call last): 

1266 VdtValueTooLongError: the value "(1, 2.0, '1.2.3.4', 'a', 1, 'b')" is too long. 

1267 >>> vtor.check(mix_str, 0) 

1268 Traceback (most recent call last): 

1269 VdtTypeError: the value "0" is of the wrong type. 

1270 

1271 >>> vtor.check('mixed_list("yoda")', ('a')) 

1272 Traceback (most recent call last): 

1273 VdtParamError: passed an incorrect value "KeyError('yoda',)" for parameter "'mixed_list'" 

1274 """ 

1275 try: 

1276 length = len(value) 

1277 except TypeError: 

1278 raise VdtTypeError(value) 

1279 if length < len(args): 

1280 raise VdtValueTooShortError(value) 

1281 elif length > len(args): 

1282 raise VdtValueTooLongError(value) 

1283 try: 

1284 return [fun_dict[arg](val) for arg, val in zip(args, value)] 

1285 except KeyError as e: 

1286 raise VdtParamError('mixed_list', e) 

1287 

1288 

1289def is_option(value, *options): 

1290 """ 

1291 This check matches the value to any of a set of options. 

1292  

1293 >>> vtor.check('option("yoda", "jedi")', 'yoda') 

1294 'yoda' 

1295 >>> vtor.check('option("yoda", "jedi")', 'jed') 

1296 Traceback (most recent call last): 

1297 VdtValueError: the value "jed" is unacceptable. 

1298 >>> vtor.check('option("yoda", "jedi")', 0) 

1299 Traceback (most recent call last): 

1300 VdtTypeError: the value "0" is of the wrong type. 

1301 """ 

1302 if not isinstance(value, str): 

1303 raise VdtTypeError(value) 

1304 if not value in options: 

1305 raise VdtValueError(value) 

1306 return value 

1307 

1308 

1309def _test(value, *args, **keywargs): 

1310 """ 

1311 A function that exists for test purposes. 

1312  

1313 >>> checks = [ 

1314 ... '3, 6, min=1, max=3, test=list(a, b, c)', 

1315 ... '3', 

1316 ... '3, 6', 

1317 ... '3,', 

1318 ... 'min=1, test="a b c"', 

1319 ... 'min=5, test="a, b, c"', 

1320 ... 'min=1, max=3, test="a, b, c"', 

1321 ... 'min=-100, test=-99', 

1322 ... 'min=1, max=3', 

1323 ... '3, 6, test="36"', 

1324 ... '3, 6, test="a, b, c"', 

1325 ... '3, max=3, test=list("a", "b", "c")', 

1326 ... '''3, max=3, test=list("'a'", 'b', "x=(c)")''', 

1327 ... "test='x=fish(3)'", 

1328 ... ] 

1329 >>> v = Validator({'test': _test}) 

1330 >>> for entry in checks: 

1331 ... pprint(v.check(('test(%s)' % entry), 3)) 

1332 (3, ('3', '6'), {'max': '3', 'min': '1', 'test': ['a', 'b', 'c']}) 

1333 (3, ('3',), {}) 

1334 (3, ('3', '6'), {}) 

1335 (3, ('3',), {}) 

1336 (3, (), {'min': '1', 'test': 'a b c'}) 

1337 (3, (), {'min': '5', 'test': 'a, b, c'}) 

1338 (3, (), {'max': '3', 'min': '1', 'test': 'a, b, c'}) 

1339 (3, (), {'min': '-100', 'test': '-99'}) 

1340 (3, (), {'max': '3', 'min': '1'}) 

1341 (3, ('3', '6'), {'test': '36'}) 

1342 (3, ('3', '6'), {'test': 'a, b, c'}) 

1343 (3, ('3',), {'max': '3', 'test': ['a', 'b', 'c']}) 

1344 (3, ('3',), {'max': '3', 'test': ["'a'", 'b', 'x=(c)']}) 

1345 (3, (), {'test': 'x=fish(3)'}) 

1346  

1347 >>> v = Validator() 

1348 >>> v.check('integer(default=6)', '3') 

1349 3 

1350 >>> v.check('integer(default=6)', None, True) 

1351 6 

1352 >>> v.get_default_value('integer(default=6)') 

1353 6 

1354 >>> v.get_default_value('float(default=6)') 

1355 6.0 

1356 >>> v.get_default_value('pass(default=None)') 

1357 >>> v.get_default_value("string(default='None')") 

1358 'None' 

1359 >>> v.get_default_value('pass') 

1360 Traceback (most recent call last): 

1361 KeyError: 'Check "pass" has no default value.' 

1362 >>> v.get_default_value('pass(default=list(1, 2, 3, 4))') 

1363 ['1', '2', '3', '4'] 

1364  

1365 >>> v = Validator() 

1366 >>> v.check("pass(default=None)", None, True) 

1367 >>> v.check("pass(default='None')", None, True) 

1368 'None' 

1369 >>> v.check('pass(default="None")', None, True) 

1370 'None' 

1371 >>> v.check('pass(default=list(1, 2, 3, 4))', None, True) 

1372 ['1', '2', '3', '4'] 

1373  

1374 Bug test for unicode arguments 

1375 >>> v = Validator() 

1376 >>> v.check('string(min=4)', 'test') == 'test' 

1377 True 

1378  

1379 >>> v = Validator() 

1380 >>> v.get_default_value('string(min=4, default="1234")') == '1234' 

1381 True 

1382 >>> v.check('string(min=4, default="1234")', 'test') == 'test' 

1383 True 

1384  

1385 >>> v = Validator() 

1386 >>> default = v.get_default_value('string(default=None)') 

1387 >>> default == None 

1388 1 

1389 """ 

1390 return (value, args, keywargs) 

1391 

1392 

1393def _test2(): 

1394 """ 

1395 >>>  

1396 >>> v = Validator() 

1397 >>> v.get_default_value('string(default="#ff00dd")') 

1398 '#ff00dd' 

1399 >>> v.get_default_value('integer(default=3) # comment') 

1400 3 

1401 """ 

1402 

1403def _test3(): 

1404 r""" 

1405 >>> vtor.check('string(default="")', '', missing=True) 

1406 '' 

1407 >>> vtor.check('string(default="\n")', '', missing=True) 

1408 '\n' 

1409 >>> print(vtor.check('string(default="\n")', '', missing=True)) 

1410 <BLANKLINE> 

1411 <BLANKLINE> 

1412 >>> vtor.check('string()', '\n') 

1413 '\n' 

1414 >>> vtor.check('string(default="\n\n\n")', '', missing=True) 

1415 '\n\n\n' 

1416 >>> vtor.check('string()', 'random \n text goes here\n\n') 

1417 'random \n text goes here\n\n' 

1418 >>> vtor.check('string(default=" \nrandom text\ngoes \n here\n\n ")', 

1419 ... '', missing=True) 

1420 ' \nrandom text\ngoes \n here\n\n ' 

1421 >>> vtor.check("string(default='\n\n\n')", '', missing=True) 

1422 '\n\n\n' 

1423 >>> vtor.check("option('\n','a','b',default='\n')", '', missing=True) 

1424 '\n' 

1425 >>> vtor.check("string_list()", ['foo', '\n', 'bar']) 

1426 ['foo', '\n', 'bar'] 

1427 >>> vtor.check("string_list(default=list('\n'))", '', missing=True) 

1428 ['\n'] 

1429 """ 

1430 

1431 

1432if __name__ == '__main__': 

1433 # run the code tests in doctest format 

1434 import sys 

1435 import doctest 

1436 m = sys.modules.get('__main__') 

1437 globs = m.__dict__.copy() 

1438 globs.update({ 

1439 'vtor': Validator(), 

1440 }) 

1441 

1442 failures, tests = doctest.testmod( 

1443 m, globs=globs, 

1444 optionflags=doctest.IGNORE_EXCEPTION_DETAIL | doctest.ELLIPSIS) 

1445 assert not failures, '{} failures out of {} tests'.format(failures, tests)