1
===================================
2
Validation Schema with validate.py
3
===================================
5
--------------------------
6
Using the Validator class
7
--------------------------
10
:Authors: `Michael Foord`_, `Nicola Larosa`_, `Mark Andrews`_
11
:Version: Validate 0.2.0
13
:Homepage: `Validate Homepage`_
14
:License: `BSD License`_
15
:Support: `Mailing List`_
17
.. _Mailing List: http://lists.sourceforge.net/lists/listinfo/configobj-develop
18
.. _Michael Foord: fuzzyman@voidspace.org.uk
19
.. _Nicola Larosa: nico@teknico.net
20
.. _Mark Andrews: mark@la-la.com
22
.. _Validate Homepage: http://www.voidspace.org.uk/python/validate.html
23
.. _BSD License: http://www.voidspace.org.uk/documents/BSD-LICENSE.txt
26
.. contents:: Validate Manual
31
Validation is used to check that supplied values conform to a specification.
33
The value can be supplied as a string, e.g. from a config file. In this case
34
the check will also *convert* the value to the required type. This allows you
35
to add validation as a transparent layer to access data stored as strings. The
36
validation checks that the data is correct *and* converts it to the expected
39
Checks are also strings, and are easy to write. One generic system can be used
40
to validate information from different sources, via a single consistent
43
Checks look like function calls, and map to function calls. They can include
44
parameters and keyword arguments. These arguments are passed to the relevant
45
function by the ``Validator`` instance, along with the value being checked.
47
The syntax for checks also allows for specifying a default value. This default
48
value can be ``None``, no matter what the type of the check. This can be used
49
to indicate that a value was missing, and so holds no useful value.
51
Functions either return a new value, or raise an exception. See `Validator
52
Exceptions`_ for the low down on the exception classes that ``validate.py``
55
Some standard functions are provided, for basic data types; these come built
56
into every validator. Additional checks are easy to write: they can be provided
57
when the ``Validator`` is instantiated, or added afterwards.
59
Validate was primarily written to support ConfigObj_, but was designed to be
60
applicable to many other situations.
62
For support and bug reports please use the ConfigObj `Mailing List`_.
64
.. _ConfigObj: http://www.voidspace.org.uk/python/configobj.html
69
The current version is **0.2.0**, dated 25th August 2005.
71
You can get obtain validate in the following ways :
76
* validate.py_ from Voidspace
78
* configobj.zip from Voidspace - See the homepage of ConfigObj_ for the latest
79
version and downlaod links.
81
This contains validate.py and `this document`_. (As well as ConfigObj_ and
82
the ConfigObj documentation).
84
* The latest development version can be obtained from the `Subversion Repository`_.
89
*configobj.zip* contains `this document`_ and full `API Docs`_, generated
90
automatically by EpyDoc_.
92
* You can view `this document`_ online as the `Validate Homepage`_.
94
* You can also browse the `API Docs`_ online.
99
Validate_ is also part of the Pythonutils_ set of modules. This contains
100
various other useful helper modules, and is required by many of the `Voidspace
103
.. _configobj.py: http://www.voidspace.org.uk/cgi-bin/voidspace/downman.py?file=configobj.py
104
.. _configobj.zip: http://www.voidspace.org.uk/cgi-bin/voidspace/downman.py?file=configobj-4.0.0b4.zip
105
.. _validate.py: http://www.voidspace.org.uk/cgi-bin/voidspace/downman.py?file=validate.py
106
.. _API Docs: http://www.voidspace.org.uk/python/configobj-api/
107
.. _Subversion Repository: http://svn.rest2web.python-hosting.com/branches/configobj4/
108
.. _Sourceforge: http://sourceforge.net/projects/configobj
109
.. _EpyDoc: http://epydoc.sourceforge.net
110
.. _pythonutils: http://www.voidspace.org.uk/python/pythonutils.html
111
.. _Voidspace Python Projects: http://www.voidspace.org.uk/python
112
.. _validate: http://www.voidspace.org.uk/python/validate.html
115
The standard functions
116
======================
118
The standard functions come built-in to every ``Validator`` instance. They work
119
with the following basic data types :
127
plus lists of these datatypes.
129
Adding additional checks is done through coding simple functions.
131
The full set of standard checks are :
133
:'integer': matches integer values (including negative). Takes optional 'min'
134
and 'max' arguments : ::
137
integer(3, 9) # any value from 3 to 9
138
integer(min=0) # any positive value
141
:'float': matches float values
142
Has the same parameters as the integer check.
144
:'bool': matches boolean values: ``True`` or ``False``.
145
Acceptable string values for True are : ::
149
Acceptable string values for False are : ::
153
Any other value raises an error.
155
:'string': matches any string. Takes optional keyword args 'min' and 'max' to
156
specify min and max length of string.
158
:'ip_addr': matches an Internet Protocol address, v.4, represented by a
159
dotted-quad string, i.e. '1.2.3.4'.
161
:'list': matches any list. Takes optional keyword args 'min', and 'max' to
162
specify min and max sizes of the list.
164
:'int_list': Matches a list of integers. Takes the same arguments as list.
166
:'float_list': Matches a list of floats. Takes the same arguments as list.
168
:'bool_list': Matches a list of boolean values. Takes the same arguments as
171
:'string_list': Matches a list of strings. Takes the same arguments as list.
173
:'ip_addr_list': Matches a list of IP addresses. Takes the same arguments as
176
:'mixed_list': Matches a list with different types in specific positions.
177
List size must match the number of arguments.
179
Each position can be one of : ::
181
int, str, bool, float, ip_addr
183
So to specify a list with two strings followed by two integers,
184
you write the check as : ::
186
mixed_list(str, str, int, int)
188
:'pass': matches everything: it never fails and the value is unchanged. It is
189
also the default if no check is specified.
191
:'option': matches any from a list of options.
192
You specify this test with : ::
194
option('option 1', 'option 2', 'option 3')
196
The following code will work without you having to specifically add the
203
from validate import Validator
206
newval1 = vtor.check(value1, 'integer')
207
newval2 = vtor.check(value2, 'bool')
214
Of course, if these checks fail they raise exceptions. So you should wrap
215
them in ``try...except`` blocks. Better still, use ConfigObj for a higher
221
Using ``Validator`` is very easy. It has one public attribute and one public
224
Shown below are the different steps in using ``Validator``.
226
The only additional thing you need to know, is about `Writing check
236
from validate import Validator
247
from validate import Validator
250
'check_name1': function1,
251
'check_name2': function2,
252
'check_name3': function3,
255
vtor = Validator(fdict)
259
The second method adds a set of your functions as soon as your validator is
260
created. They are stored in the ``vtor.functions`` dictionary. The 'key' you
261
give them in this dictionary is the name you use in your checks (not the
262
original function name).
264
Dictionary keys/functions you pass in can override the built-in ones if you
270
The code shown above, for adding functions on instantiation, has exactly the
271
same effect as the following code :
277
from validate import Validator
280
vtor.functions['check_name1'] = function1
281
vtor.functions['check_name2'] = function2
282
vtor.functions['check_name3'] = function3
286
``vtor.functions``is just a dictionary that maps names to functions, so we
287
could also have called ``vtor.functions.update(fdict)``.
292
As we've heard, the checks map to the names in the ``functions`` dictionary.
293
You've got a full list of `The standard functions`_ and the arguments they
296
If you're using ``Validator`` from ConfigObj, then your checks will look like
299
keyword = int_list(max=6)
301
but the check part will be identical .
306
If you're not using ``Validator`` from ConfigObj, then you'll need to call the
307
``check`` method yourself.
309
If the check fails then it will raise an exception, so you'll want to trap
310
that. Here's the basic example :
316
from validate import Validator, ValidateError
319
check = "integer(0, 9)"
322
newvalue = vtor.check(check, value)
323
except ValidateError:
324
print 'Check Failed.'
326
print 'Check passed.'
332
Although the value can be a string, if it represents a list it should
333
already have been turned into a list of strings.
338
Some values may not be available, and you may want to be able to specify a
339
default as part of the check.
341
You do this by passing the keyword ``missing=True`` to the ``check`` method, as
342
well as a ``default=value`` in the check. (Constructing these checks is done
343
automatically by ConfigObj: you only need to know about the ``default=value``
350
check1 = 'integer(default=50)'
351
check2 = 'option("val 1", "val 2", "val 3", default="val 1")'
353
assert vtor.check('', check1, missing=True) == 50
354
assert vtor.check('', check2, missing=True) == "val 1"
358
If you pass in ``missing=True`` to the check method, then the actual value is
359
ignored. If no default is specified in the check, a ``ValidateMissingValue``
360
exception is raised. If a default is specified then that is passed to the
363
If the check has ``default=None`` (case sensitive) then ``vtor.check`` will
364
*always* return ``None`` (the object). This makes it easy to tell your program
365
that this check contains no useful value when missing, i.e. the value is
366
optional, and may be omitted without harm.
373
If you only use Validator through ConfigObj, it traps these Exceptions for
374
you. You will still need to know about them for writing your own check
377
``vtor.check`` indicates that the check has failed by raising an exception.
378
The appropriate error should be raised in the check function.
380
The base error class is ``ValidateError``. All errors (except for ``VdtParamError``)
381
raised are sub-classes of this.
383
If an unrecognised check is specified then ``VdtUnknownCheckError`` is
386
There are also ``VdtTypeError`` and ``VdtValueError``.
388
If incorrect parameters are passed to a check function then it will (or should)
389
raise ``VdtParamError``. As this indicates *programmer* error, rather than an error
390
in the value, it is a subclass of ``SyntaxError`` instead of ``ValidateError``.
394
This means it *won't* be caught by ConfigObj - but propagated instead.
396
If the value supplied is the wrong type, then the check should raise
397
``VdtTypeError``. e.g. the check requires the value to be an integer (or
398
representation of an integer) and something else was supplied.
400
If the value supplied is the right type, but an unacceptable value, then the
401
check should raise ``VdtValueError``. e.g. the check requires the value to
402
be an integer (or representation of an integer) less than ten and a higher
405
Both ``VdtTypeError`` and ``VdtValueError`` are initialised with the
406
incorrect value. In other words you raise them like this :
412
raise VdtTypeError(value)
414
raise VdtValueError(value)
418
``VdtValueError`` has the following subclasses, which should be raised if
419
they are more appropriate.
421
* ``VdtValueTooSmallError``
422
* ``VdtValueTooBigError``
423
* ``VdtValueTooShortError``
424
* ``VdtValueTooLongError``
426
Writing check functions
427
=======================
429
Writing check functions is easy.
431
The check function will receive the value as its first argument, followed by
432
any other parameters and keyword arguments.
434
If the check fails, it should raise a ``VdtTypeError`` or a
435
``VdtValueError`` (or an appropriate subclass).
437
All parameters and keyword arguments are *always* passed as strings. (Parsed
438
from the check string).
440
The value might be a string (or list of strings) and need
441
converting to the right type - alternatively it might already be a list of
442
integers. Our function needs to be able to handle either.
444
If the check passes then it should return the value (possibly converted to the
452
Here is an example function that requires a list of integers. Each integer
453
must be between 0 and 99.
455
It takes a single argument specifying the length of the list. (Which allows us
456
to use the same check in more than one place). If the length can't be converted
457
to an integer then we need to raise ``VdtParamError``.
459
Next we check that the value is a list. Anything else should raise a
460
``VdtTypeError``. The list should also have 'length' entries. If the list
461
has more or less entries then we will need to raise a
462
``VdtValueTooShortError`` or a ``VdtValueTooLongError``.
464
Then we need to check every entry in the list. Each entry should be an integer
465
between 0 and 99, or a string representation of an integer between 0 and 99.
466
Any other type is a ``VdtTypeError``, any other value is a
467
``VdtValueError`` (either too big, or too small).
473
def special_list(value, length):
475
Check that the supplied value is a list of integers,
476
with 'length' entries, and each entry between 0 and 99.
478
# length is supplied as a string
479
# we need to convert it to an integer
483
raise VdtParamError('length', length)
485
# Check the supplied value is a list
486
if not isinstance(value, list):
487
raise VdtTypeError(value)
489
# check the length of the list is correct
490
if len(value) > length:
491
raise VdtValueTooLongError(value)
492
elif len(value) < length:
493
raise VdtValueTooShortError(value)
495
# Next, check every member in the list
496
# converting strings as necessary
499
if not isinstance(entry, (str, unicode, int)):
500
# a value in the list
501
# is neither an integer nor a string
502
raise VdtTypeError(value)
503
elif isinstance(entry, (str, unicode)):
504
if not entry.isdigit():
505
raise VdtTypeError(value)
509
raise VdtValueTooSmallError(value)
511
raise VdtValueTooBigError(value)
514
# if we got this far, all is well
515
# return the new list
520
If you are only using validate from ConfigObj then the error type (*TooBig*,
521
*TooSmall*, etc) is lost - so you may only want to raise ``VdtValueError``.
525
If your function raises an exception that isn't a subclass of
526
``ValidateError``, then ConfigObj won't trap it. This means validation will
529
This is why our function starts by checking the type of the value. If we
530
are passed the wrong type (e.g. an integer rather than a list) we get a
531
``VdtTypeError`` rather than bombing out when we try to iterate over
534
If you are using validate in another circumstance you may want to create your
535
own subclasses of ``ValidateError``, that convey more specific information.
540
* A regex check function ?
541
* A timestamp check function ? (Using the ``parse`` function from ``DateUtil``).
542
* Allow triple quotes ? (getting a bit heavy for a single regex)
549
Please file any bug reports to `Michael Foord`_ or the ConfigObj
552
Lists passed as function arguments need additional quotes. Ugly, could do
555
If we could pull tuples out of arguments, it would be easier
556
to specify arguments for 'mixed_lists'.
562
2005/08/18 Version 0.2.0
563
-----------------------------
565
Updated by `Michael Foord`_ and `Nicola Larosa`_
567
Does type conversion as well.
569
2005/02/01 Version 0.1.0
570
-----------------------------
572
Initial version developed by `Michael Foord`_
577
Rendering this document with docutils also needs the
578
textmacros module and the PySrc CSS stuff. See
579
http://www.voidspace.org.uk/python/firedrop2/textmacros.shtml
584
<a href="http://www.python.org">
585
<img src="images/powered_by_python.jpg" width="602" height="186" border="0" />
587
<a href="http://www.opensource.org">
588
<img src="images/osi-certified-120x100.gif" width="120" height="100" border="0" />
589
<br /><strong>Certified Open Source</strong>
592
<script type="text/javascript" language="JavaScript">var site="s16atlantibots"</script>
593
<script type="text/javascript" language="JavaScript1.2" src="http://s16.sitemeter.com/js/counter.js?site=s16atlantibots"></script>
595
<a href="http://s16.sitemeter.com/stats.asp?site=s16atlantibots">
596
<img src="http://s16.sitemeter.com/meter.asp?site=s16atlantibots" alt="Site Meter" border=0 />