/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
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`_
11
:Version: Validate 0.2.0
12
:Date: 2005/08/25
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
23
.. _BSD License: http://www.voidspace.org.uk/documents/BSD-LICENSE.txt
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
59
Validate was primarily written to support ConfigObj_, but was designed to be 
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
69
The current version is **0.2.0**, dated 25th August 2005. 
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 
79
  version and downlaod links.
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
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
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()
206
    newval1 = vtor.check(value1, 'integer')
207
    newval2 = vtor.check(value2, 'bool')
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
218
Using Validator
219
===============
220
221
Using ``Validator`` is very easy. It has one public attribute and one public
222
method.
223
224
Shown below are the different steps in using ``Validator``.
225
226
The only additional thing you need to know, is about `Writing check
227
functions`_.
228
229
Instantiate
230
-----------
231
232
.. raw:: html
233
234
    {+coloring}
235
236
    from validate import Validator
237
    vtor = Validator()
238
239
    {-coloring}
240
241
or even :
242
243
.. raw:: html
244
245
    {+coloring}
246
247
    from validate import Validator
248
    #
249
    fdict = {
250
        'check_name1': function1,
251
        'check_name2': function2,
252
        'check_name3': function3,
253
    }
254
    #
255
    vtor = Validator(fdict)
256
257
    {-coloring}
258
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).
263
264
Dictionary keys/functions you pass in can override the built-in ones if you
265
want.
266
267
Adding functions
268
----------------
269
270
The code shown above, for adding functions on instantiation, has exactly the
271
same effect as the following code :
272
273
.. raw:: html
274
275
    {+coloring}
276
277
    from validate import Validator
278
    #
279
    vtor = Validator()
280
    vtor.functions['check_name1'] = function1
281
    vtor.functions['check_name2'] = function2
282
    vtor.functions['check_name3'] = function3
283
284
    {-coloring}
285
286
``vtor.functions``is just a dictionary that maps names to functions, so we
287
could also have called ``vtor.functions.update(fdict)``.
288
289
Writing the check
290
-----------------
291
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
294
take.
295
296
If you're using ``Validator`` from ConfigObj, then your checks will look like
297
: ::
298
299
    keyword = int_list(max=6)
300
301
but the check part will be identical .
302
303
The check method
304
----------------
305
306
If you're not using ``Validator`` from ConfigObj, then you'll need to call the
307
``check`` method yourself.
308
309
If the check fails then it will raise an exception, so you'll want to trap
310
that. Here's the basic example :
311
312
.. raw:: html
313
314
    {+coloring}
315
316
    from validate import Validator, ValidateError
317
    #
318
    vtor = Validator()
319
    check = "integer(0, 9)"
320
    value = 3
321
    try:
322
        newvalue = vtor.check(check, value)
323
    except ValidateError:
324
        print 'Check Failed.'
325
    else:
326
        print 'Check passed.'
327
328
    {-coloring}
329
330
.. caution::
331
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.
334
335
Default Values
336
~~~~~~~~~~~~~~
337
338
Some values may not be available, and you may want to be able to specify a
339
default as part of the check.
340
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``
344
part) :
345
346
.. raw:: html
347
348
    {+coloring}
349
350
    check1 = 'integer(default=50)'
351
    check2 = 'option("val 1", "val 2", "val 3", default="val 1")'
352
353
    assert vtor.check('', check1, missing=True) == 50
354
    assert vtor.check('', check2, missing=True) == "val 1"
355
356
    {-coloring}
357
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
361
check instead.
362
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.
367
368
Validator Exceptions
369
====================
370
371
.. note::
372
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
375
    functions.
376
377
``vtor.check`` indicates that the check has failed by raising an exception.
378
The appropriate error should be raised in the check function.
379
380
The base error class is ``ValidateError``. All errors (except for ``VdtParamError``) 
381
raised are sub-classes of this.
382
383
If an unrecognised check is specified then ``VdtUnknownCheckError`` is
384
raised.
385
386
There are also ``VdtTypeError`` and ``VdtValueError``.
387
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``. 
391
392
.. note::
393
394
    This means it *won't* be caught by ConfigObj - but propagated instead.
395
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.
399
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
403
value was supplied.
404
405
Both ``VdtTypeError`` and ``VdtValueError`` are initialised with the
406
incorrect value. In other words you raise them like this :
407
408
.. raw:: html
409
410
    {+coloring}
411
412
    raise VdtTypeError(value)
413
    #
414
    raise VdtValueError(value)
415
416
    {-coloring}
417
418
``VdtValueError`` has the following subclasses, which should be raised if
419
they are more appropriate.
420
421
* ``VdtValueTooSmallError``
422
* ``VdtValueTooBigError``
423
* ``VdtValueTooShortError``
424
* ``VdtValueTooLongError``
425
426
Writing check functions
427
=======================
428
429
Writing check functions is easy.
430
431
The check function will receive the value as its first argument, followed by
432
any other parameters and keyword arguments.
433
434
If the check fails, it should raise a ``VdtTypeError`` or a
435
``VdtValueError`` (or an appropriate subclass).
436
437
All parameters and keyword arguments are *always* passed as strings. (Parsed
438
from the check string).
439
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.
443
444
If the check passes then it should return the value (possibly converted to the
445
right type).
446
447
And that's it !
448
449
Example
450
-------
451
452
Here is an example function that requires a list of integers. Each integer
453
must be between 0 and 99.
454
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``.
458
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``.
463
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).
468
469
.. raw:: html
470
471
    {+coloring}
472
473
    def special_list(value, length):
474
        """
475
        Check that the supplied value is a list of integers,
476
        with 'length' entries, and each entry between 0 and 99.
477
        """
478
        # length is supplied as a string
479
        # we need to convert it to an integer
480
        try:
481
            length = int(length)
482
        except ValueError:
483
            raise VdtParamError('length', length)
484
        #
485
        # Check the supplied value is a list
486
        if not isinstance(value, list):
487
            raise VdtTypeError(value)
488
        #
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)
494
        #
495
        # Next, check every member in the list
496
        # converting strings as necessary
497
        out = []
498
        for entry in value:
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)
506
                else:
507
                    entry = int(entry)
508
            if entry < 0:
509
                raise VdtValueTooSmallError(value)
510
            elif entry > 99:
511
                raise VdtValueTooBigError(value)
512
            out.append(entry)
513
        #
514
        # if we got this far, all is well
515
        # return the new list
516
        return out
517
518
    {-coloring}
519
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``.
522
523
.. caution::
524
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 
527
    fail.
528
    
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 
532
    the value.
533
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.
536
537
TODO
538
====
539
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)
543
544
ISSUES
545
======
546
547
.. note::
548
549
    Please file any bug reports to `Michael Foord`_ or the ConfigObj
550
    `Mailing List`_.
551
552
Lists passed as function arguments need additional quotes. Ugly, could do
553
with fixing this.
554
555
If we could pull tuples out of arguments, it would be easier
556
to specify arguments for 'mixed_lists'.
557
558
CHANGELOG
559
=========
560
561
562
2005/08/18      Version 0.2.0
563
-----------------------------
564
565
Updated by `Michael Foord`_ and `Nicola Larosa`_
566
567
Does type conversion as well.
568
569
2005/02/01      Version 0.1.0
570
-----------------------------
571
572
Initial version developed by `Michael Foord`_
573
and `Mark Andrews`_
574
575
.. note::
576
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
580
581
.. raw:: html
582
583
    <div align="center">
584
        <a href="http://www.python.org">
585
            <img src="images/powered_by_python.jpg" width="602" height="186" border="0" />
586
        </a>
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>
590
        </a>
591
        <br /><br />
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>
594
        <noscript>
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 />
597
            </a>
598
        </noscript>
599
    </div>