~bzr-pqm/bzr/bzr.dev

1185.12.49 by Aaron Bentley
Switched to ConfigObj
1
===================================
2
 Validation Schema with validate.py
3
===================================
4
5
--------------------------
6
 Using the Validator class
7
--------------------------
8
9
10
:Authors: `Michael Foord`_, `Nicola Larosa`_, `Mark Andrews`_
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
11
:Version: Validate 0.2.1
12
:Date: 2005/12/16
1185.12.49 by Aaron Bentley
Switched to ConfigObj
13
:Homepage: `Validate Homepage`_
14
:License: `BSD License`_
15
:Support: `Mailing List`_
16
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
21
.. _This Document:
22
.. _Validate Homepage: http://www.voidspace.org.uk/python/validate.html
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
23
.. _BSD License: http://www.voidspace.org.uk/python/license.shtml
1185.12.49 by Aaron Bentley
Switched to ConfigObj
24
25
26
.. contents:: Validate Manual
27
28
Introduction
29
============
30
31
Validation is used to check that supplied values conform to a specification.
32
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
37
type.
38
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
41
mechanism.
42
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.
46
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.
50
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``
53
defines.
54
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.
58
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
59
Validate was primarily written to support ConfigObj_, but is designed to be 
1185.12.49 by Aaron Bentley
Switched to ConfigObj
60
applicable to many other situations.
61
62
For support and bug reports please use the ConfigObj `Mailing List`_.
63
64
.. _ConfigObj: http://www.voidspace.org.uk/python/configobj.html
65
66
Downloading
67
===========
68
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
69
The current version is **0.2.1**, dated 16th December 2005. 
1185.12.49 by Aaron Bentley
Switched to ConfigObj
70
71
You can get obtain validate in the following ways :
72
73
Files
74
-----
75
76
* validate.py_ from Voidspace
77
78
* configobj.zip from Voidspace - See the homepage of ConfigObj_ for the latest 
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
79
  version and download links.
1185.12.49 by Aaron Bentley
Switched to ConfigObj
80
81
    This contains validate.py and `this document`_. (As well as ConfigObj_ and 
82
    the ConfigObj documentation).
83
    
84
* The latest development version can be obtained from the `Subversion Repository`_.
85
86
Documentation
87
-------------
88
89
*configobj.zip* contains `this document`_ and full `API Docs`_, generated 
90
automatically by EpyDoc_.
91
92
* You can view `this document`_ online as the `Validate Homepage`_.
93
94
* You can also browse the `API Docs`_ online.
95
96
Pythonutils
97
-----------
98
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 
101
Python Projects`_.
102
103
.. _configobj.py: http://www.voidspace.org.uk/cgi-bin/voidspace/downman.py?file=configobj.py
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
104
.. _configobj.zip: http://www.voidspace.org.uk/cgi-bin/voidspace/downman.py?file=configobj-4.1.0.zip
1185.12.49 by Aaron Bentley
Switched to ConfigObj
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
113
114
115
The standard functions
116
======================
117
118
The standard functions come built-in to every ``Validator`` instance. They work
119
with the following basic data types :
120
121
* integer
122
* float
123
* boolean
124
* string
125
* ip_addr
126
127
plus lists of these datatypes.
128
129
Adding additional checks is done through coding simple functions.
130
131
The full set of standard checks are :
132
133
:'integer': matches integer values (including negative). Takes optional 'min'
134
            and 'max' arguments : ::
135
136
                integer()
137
                integer(3, 9)    # any value from 3 to 9
138
                integer(min=0) # any positive value
139
                integer(max=9)
140
141
:'float': matches float values
142
          Has the same parameters as the integer check.
143
144
:'bool': matches boolean values: ``True`` or ``False``.
145
         Acceptable string values for True are : ::
146
147
             true, on, yes, 1
148
149
         Acceptable string values for False are : ::
150
151
             false, off, no, 0
152
153
         Any other value raises an error.
154
155
:'string': matches any string. Takes optional keyword args 'min' and 'max' to
156
           specify min and max length of string.
157
158
:'ip_addr': matches an Internet Protocol address, v.4, represented by a
159
            dotted-quad string, i.e. '1.2.3.4'.
160
161
:'list': matches any list. Takes optional keyword args 'min', and 'max' to
162
         specify min and max sizes of the list.
163
164
:'int_list': Matches a list of integers. Takes the same arguments as list.
165
166
:'float_list': Matches a list of floats. Takes the same arguments as list.
167
168
:'bool_list': Matches a list of boolean values. Takes the same arguments as
169
              list.
170
171
:'string_list': Matches a list of strings. Takes the same arguments as list.
172
173
:'ip_addr_list': Matches a list of IP addresses. Takes the same arguments as
174
                 list.
175
176
:'mixed_list': Matches a list with different types in specific positions.
177
               List size must match the number of arguments.
178
179
               Each position can be one of : ::
180
181
                   int, str, bool, float, ip_addr
182
183
               So to specify a list with two strings followed by two integers,
184
               you write the check as : ::
185
186
                   mixed_list(str, str, int, int)
187
188
:'pass': matches everything: it never fails and the value is unchanged. It is
189
         also the default if no check is specified.
190
191
:'option': matches any from a list of options.
192
           You specify this test with : ::
193
194
               option('option 1', 'option 2', 'option 3')
195
196
The following code will work without you having to specifically add the
197
functions yourself.
198
199
.. raw:: html
200
201
    {+coloring}
202
203
    from validate import Validator
204
    #
205
    vtor = Validator()
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
206
    newval1 = vtor.check('integer', value1)
207
    newval2 = vtor.check('bool', value2)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
208
    # etc ...
209
210
    {-coloring}
211
212
.. note::
213
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
216
    level interface.
217
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
218
1185.12.49 by Aaron Bentley
Switched to ConfigObj
219
Using Validator
220
===============
221
222
Using ``Validator`` is very easy. It has one public attribute and one public
223
method.
224
225
Shown below are the different steps in using ``Validator``.
226
227
The only additional thing you need to know, is about `Writing check
228
functions`_.
229
230
Instantiate
231
-----------
232
233
.. raw:: html
234
235
    {+coloring}
236
237
    from validate import Validator
238
    vtor = Validator()
239
240
    {-coloring}
241
242
or even :
243
244
.. raw:: html
245
246
    {+coloring}
247
248
    from validate import Validator
249
    #
250
    fdict = {
251
        'check_name1': function1,
252
        'check_name2': function2,
253
        'check_name3': function3,
254
    }
255
    #
256
    vtor = Validator(fdict)
257
258
    {-coloring}
259
260
The second method adds a set of your functions as soon as your validator is
261
created. They are stored in the ``vtor.functions`` dictionary. The 'key' you
262
give them in this dictionary is the name you use in your checks (not the
263
original function name).
264
265
Dictionary keys/functions you pass in can override the built-in ones if you
266
want.
267
268
Adding functions
269
----------------
270
271
The code shown above, for adding functions on instantiation, has exactly the
272
same effect as the following code :
273
274
.. raw:: html
275
276
    {+coloring}
277
278
    from validate import Validator
279
    #
280
    vtor = Validator()
281
    vtor.functions['check_name1'] = function1
282
    vtor.functions['check_name2'] = function2
283
    vtor.functions['check_name3'] = function3
284
285
    {-coloring}
286
287
``vtor.functions``is just a dictionary that maps names to functions, so we
288
could also have called ``vtor.functions.update(fdict)``.
289
290
Writing the check
291
-----------------
292
293
As we've heard, the checks map to the names in the ``functions`` dictionary.
294
You've got a full list of `The standard functions`_ and the arguments they
295
take.
296
297
If you're using ``Validator`` from ConfigObj, then your checks will look like
298
: ::
299
300
    keyword = int_list(max=6)
301
302
but the check part will be identical .
303
304
The check method
305
----------------
306
307
If you're not using ``Validator`` from ConfigObj, then you'll need to call the
308
``check`` method yourself.
309
310
If the check fails then it will raise an exception, so you'll want to trap
311
that. Here's the basic example :
312
313
.. raw:: html
314
315
    {+coloring}
316
317
    from validate import Validator, ValidateError
318
    #
319
    vtor = Validator()
320
    check = "integer(0, 9)"
321
    value = 3
322
    try:
323
        newvalue = vtor.check(check, value)
324
    except ValidateError:
325
        print 'Check Failed.'
326
    else:
327
        print 'Check passed.'
328
329
    {-coloring}
330
331
.. caution::
332
333
    Although the value can be a string, if it represents a list it should
334
    already have been turned into a list of strings.
335
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
336
1185.12.49 by Aaron Bentley
Switched to ConfigObj
337
Default Values
338
~~~~~~~~~~~~~~
339
340
Some values may not be available, and you may want to be able to specify a
341
default as part of the check.
342
343
You do this by passing the keyword ``missing=True`` to the ``check`` method, as
344
well as a ``default=value`` in the check. (Constructing these checks is done
345
automatically by ConfigObj: you only need to know about the ``default=value``
346
part) :
347
348
.. raw:: html
349
350
    {+coloring}
351
352
    check1 = 'integer(default=50)'
353
    check2 = 'option("val 1", "val 2", "val 3", default="val 1")'
354
355
    assert vtor.check('', check1, missing=True) == 50
356
    assert vtor.check('', check2, missing=True) == "val 1"
357
358
    {-coloring}
359
360
If you pass in ``missing=True`` to the check method, then the actual value is
361
ignored. If no default is specified in the check, a ``ValidateMissingValue``
362
exception is raised. If a default is specified then that is passed to the
363
check instead.
364
365
If the check has ``default=None`` (case sensitive) then ``vtor.check`` will
366
*always* return ``None`` (the object). This makes it easy to tell your program
367
that this check contains no useful value when missing, i.e. the value is
368
optional, and may be omitted without harm.
369
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
370
371
List Values
372
~~~~~~~~~~~
373
374
It's possible that you would like your default value to be a list. It's even
375
possible that you will write your own check functions - and would like to pass
376
them keyword arguments as lists from within the check.
377
378
To avoid confusing syntax with commas and quotes you use a list constructor to
379
specify that keyword arguments are lists. This includes the ``default`` value.
380
This makes checks look something like : ::
381
382
    checkname(default=list('val1', 'val2', 'val3'))
383
1185.12.49 by Aaron Bentley
Switched to ConfigObj
384
Validator Exceptions
385
====================
386
387
.. note::
388
389
    If you only use Validator through ConfigObj, it traps these Exceptions for
390
    you. You will still need to know about them for writing your own check
391
    functions.
392
393
``vtor.check`` indicates that the check has failed by raising an exception.
394
The appropriate error should be raised in the check function.
395
396
The base error class is ``ValidateError``. All errors (except for ``VdtParamError``) 
397
raised are sub-classes of this.
398
399
If an unrecognised check is specified then ``VdtUnknownCheckError`` is
400
raised.
401
402
There are also ``VdtTypeError`` and ``VdtValueError``.
403
404
If incorrect parameters are passed to a check function then it will (or should)
405
raise ``VdtParamError``. As this indicates *programmer* error, rather than an error
406
in the value, it is a subclass of ``SyntaxError`` instead of ``ValidateError``. 
407
408
.. note::
409
410
    This means it *won't* be caught by ConfigObj - but propagated instead.
411
412
If the value supplied is the wrong type, then the check should raise
413
``VdtTypeError``. e.g. the check requires the value to be an integer (or
414
representation of an integer) and something else was supplied.
415
416
If the value supplied is the right type, but an unacceptable value, then the
417
check should raise ``VdtValueError``. e.g. the check requires the value to
418
be an integer (or representation of an integer) less than ten and a higher
419
value was supplied.
420
421
Both ``VdtTypeError`` and ``VdtValueError`` are initialised with the
422
incorrect value. In other words you raise them like this :
423
424
.. raw:: html
425
426
    {+coloring}
427
428
    raise VdtTypeError(value)
429
    #
430
    raise VdtValueError(value)
431
432
    {-coloring}
433
434
``VdtValueError`` has the following subclasses, which should be raised if
435
they are more appropriate.
436
437
* ``VdtValueTooSmallError``
438
* ``VdtValueTooBigError``
439
* ``VdtValueTooShortError``
440
* ``VdtValueTooLongError``
441
442
Writing check functions
443
=======================
444
445
Writing check functions is easy.
446
447
The check function will receive the value as its first argument, followed by
448
any other parameters and keyword arguments.
449
450
If the check fails, it should raise a ``VdtTypeError`` or a
451
``VdtValueError`` (or an appropriate subclass).
452
453
All parameters and keyword arguments are *always* passed as strings. (Parsed
454
from the check string).
455
456
The value might be a string (or list of strings) and need
457
converting to the right type - alternatively it might already be a list of 
458
integers. Our function needs to be able to handle either.
459
460
If the check passes then it should return the value (possibly converted to the
461
right type).
462
463
And that's it !
464
465
Example
466
-------
467
468
Here is an example function that requires a list of integers. Each integer
469
must be between 0 and 99.
470
471
It takes a single argument specifying the length of the list. (Which allows us
472
to use the same check in more than one place). If the length can't be converted
473
to an integer then we need to raise ``VdtParamError``.
474
475
Next we check that the value is a list. Anything else should raise a
476
``VdtTypeError``. The list should also have 'length' entries. If the list
477
has more or less entries then we will need to raise a
478
``VdtValueTooShortError`` or a ``VdtValueTooLongError``.
479
480
Then we need to check every entry in the list. Each entry should be an integer
481
between 0 and 99, or a string representation of an integer between 0 and 99.
482
Any other type is a ``VdtTypeError``, any other value is a
483
``VdtValueError`` (either too big, or too small).
484
485
.. raw:: html
486
487
    {+coloring}
488
489
    def special_list(value, length):
490
        """
491
        Check that the supplied value is a list of integers,
492
        with 'length' entries, and each entry between 0 and 99.
493
        """
494
        # length is supplied as a string
495
        # we need to convert it to an integer
496
        try:
497
            length = int(length)
498
        except ValueError:
499
            raise VdtParamError('length', length)
500
        #
501
        # Check the supplied value is a list
502
        if not isinstance(value, list):
503
            raise VdtTypeError(value)
504
        #
505
        # check the length of the list is correct
506
        if len(value) > length:
507
            raise VdtValueTooLongError(value)
508
        elif len(value) < length:
509
            raise VdtValueTooShortError(value)
510
        #
511
        # Next, check every member in the list
512
        # converting strings as necessary
513
        out = []
514
        for entry in value:
515
            if not isinstance(entry, (str, unicode, int)):
516
                # a value in the list
517
                # is neither an integer nor a string
518
                raise VdtTypeError(value)
519
            elif isinstance(entry, (str, unicode)):
520
                if not entry.isdigit():
521
                    raise VdtTypeError(value)
522
                else:
523
                    entry = int(entry)
524
            if entry < 0:
525
                raise VdtValueTooSmallError(value)
526
            elif entry > 99:
527
                raise VdtValueTooBigError(value)
528
            out.append(entry)
529
        #
530
        # if we got this far, all is well
531
        # return the new list
532
        return out
533
534
    {-coloring}
535
536
If you are only using validate from ConfigObj then the error type (*TooBig*, 
537
*TooSmall*, etc) is lost - so you may only want to raise ``VdtValueError``.
538
539
.. caution::
540
541
    If your function raises an exception that isn't a subclass of 
542
    ``ValidateError``, then ConfigObj won't trap it. This means validation will 
543
    fail.
544
    
545
    This is why our function starts by checking the type of the value. If we 
546
    are passed the wrong type (e.g. an integer rather than a list) we get a 
547
    ``VdtTypeError`` rather than bombing out when we try to iterate over 
548
    the value.
549
550
If you are using validate in another circumstance you may want to create your 
551
own subclasses of ``ValidateError``, that convey more specific information.
552
553
TODO
554
====
555
556
* A regex check function ?
557
* A timestamp check function ? (Using the ``parse`` function from ``DateUtil``).
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
558
* Allow triple quotes ? (getting a bit heavy for a regex)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
559
560
ISSUES
561
======
562
563
.. note::
564
565
    Please file any bug reports to `Michael Foord`_ or the ConfigObj
566
    `Mailing List`_.
567
568
If we could pull tuples out of arguments, it would be easier
569
to specify arguments for 'mixed_lists'.
570
571
CHANGELOG
572
=========
573
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
574
2005/12/16      Version 0.2.1
575
-----------------------------
576
577
Fixed bug so we can handle keyword argument values with commas.
578
579
We now use a list constructor for passing list values to keyword arguments
580
(including ``default``) : ::
581
582
    default=list("val", "val", "val")
583
584
Added the ``_test`` test. {sm;:-)}
585
586
Moved a function call outside a try...except block.
1185.12.49 by Aaron Bentley
Switched to ConfigObj
587
588
2005/08/18      Version 0.2.0
589
-----------------------------
590
591
Updated by `Michael Foord`_ and `Nicola Larosa`_
592
593
Does type conversion as well.
594
595
2005/02/01      Version 0.1.0
596
-----------------------------
597
598
Initial version developed by `Michael Foord`_
599
and `Mark Andrews`_
600
601
.. note::
602
603
    Rendering this document with docutils also needs the
604
    textmacros module and the PySrc CSS stuff. See
605
    http://www.voidspace.org.uk/python/firedrop2/textmacros.shtml
606
607
.. raw:: html
608
609
    <div align="center">
610
        <a href="http://www.python.org">
611
            <img src="images/powered_by_python.jpg" width="602" height="186" border="0" />
612
        </a>
613
        <a href="http://www.opensource.org">
614
            <img src="images/osi-certified-120x100.gif" width="120" height="100" border="0" />
615
            <br /><strong>Certified Open Source</strong>
616
        </a>
617
        <br /><br />
618
        <script type="text/javascript" language="JavaScript">var site="s16atlantibots"</script>
619
        <script type="text/javascript" language="JavaScript1.2" src="http://s16.sitemeter.com/js/counter.js?site=s16atlantibots"></script>
620
        <noscript>
621
            <a href="http://s16.sitemeter.com/stats.asp?site=s16atlantibots">
622
                <img src="http://s16.sitemeter.com/meter.asp?site=s16atlantibots" alt="Site Meter" border=0 />
623
            </a>
624
        </noscript>
625
    </div>