~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/util/configobj/validate.py

  • Committer: Martin Pool
  • Date: 2006-02-22 04:29:54 UTC
  • mfrom: (1566 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1569.
  • Revision ID: mbp@sourcefrog.net-20060222042954-60333f08dd56a646
[merge] from bzr.dev before integration
Fix undefined ordering in sign_my_revisions breaking tests

Show diffs side-by-side

added added

removed removed

Lines of Context:
6
6
#         nico AT tekNico DOT net
7
7
 
8
8
# This software is licensed under the terms of the BSD license.
9
 
# http://www.voidspace.org.uk/documents/BSD-LICENSE.txt
 
9
# http://www.voidspace.org.uk/python/license.shtml
10
10
# Basically you're free to copy, modify, distribute and relicense it,
11
11
# So long as you keep a copy of the license with it.
12
12
 
112
112
                You specify this check with : ::
113
113
    
114
114
                  option('option 1', 'option 2', 'option 3')
 
115
    
 
116
    You can supply a default value (returned if no value is supplied)
 
117
    using the default keyword argument.
 
118
    
 
119
    You specify a list argument for default using a list constructor syntax in
 
120
    the check : ::
 
121
    
 
122
        checkname(arg1, arg2, default=list('val 1', 'val 2', 'val 3'))
 
123
    
 
124
    A badly formatted set of arguments will raise a ``VdtParamError``.
115
125
"""
116
126
 
117
127
__docformat__ = "restructuredtext en"
118
128
 
119
 
__version__ = '0.2.0'
 
129
__version__ = '0.2.1'
120
130
 
121
131
__revision__ = '$Id: validate.py 123 2005-09-08 08:54:28Z fuzzyman $'
122
132
 
159
169
import re
160
170
StringTypes = (str, unicode)
161
171
 
 
172
 
 
173
_list_arg = re.compile(r'''
 
174
    (?:
 
175
        ([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*list\(
 
176
            (
 
177
                (?:
 
178
                    \s*
 
179
                    (?:
 
180
                        (?:".*?")|              # double quotes
 
181
                        (?:'.*?')|              # single quotes
 
182
                        (?:[^'",\s\)][^,\)]*?)  # unquoted
 
183
                    )
 
184
                    \s*,\s*
 
185
                )*
 
186
                (?:
 
187
                    (?:".*?")|              # double quotes
 
188
                    (?:'.*?')|              # single quotes
 
189
                    (?:[^'",\s\)][^,\)]*?)  # unquoted
 
190
                )?                          # last one
 
191
            )
 
192
        \)
 
193
    )
 
194
''', re.VERBOSE)    # two groups
 
195
 
 
196
_list_members = re.compile(r'''
 
197
    (
 
198
        (?:".*?")|              # double quotes
 
199
        (?:'.*?')|              # single quotes
 
200
        (?:[^'",\s=][^,=]*?)       # unquoted
 
201
    )
 
202
    (?:
 
203
    (?:\s*,\s*)|(?:\s*$)            # comma
 
204
    )
 
205
''', re.VERBOSE)    # one group
 
206
 
 
207
_paramstring = r'''
 
208
    (?:
 
209
        (
 
210
            (?:
 
211
                [a-zA-Z_][a-zA-Z0-9_]*\s*=\s*list\(
 
212
                    (?:
 
213
                        \s*
 
214
                        (?:
 
215
                            (?:".*?")|              # double quotes
 
216
                            (?:'.*?')|              # single quotes
 
217
                            (?:[^'",\s\)][^,\)]*?)       # unquoted
 
218
                        )
 
219
                        \s*,\s*
 
220
                    )*
 
221
                    (?:
 
222
                        (?:".*?")|              # double quotes
 
223
                        (?:'.*?')|              # single quotes
 
224
                        (?:[^'",\s\)][^,\)]*?)       # unquoted
 
225
                    )?                              # last one
 
226
                \)
 
227
            )|
 
228
            (?:
 
229
                (?:".*?")|              # double quotes
 
230
                (?:'.*?')|              # single quotes
 
231
                (?:[^'",\s=][^,=]*?)|       # unquoted
 
232
                (?:                         # keyword argument
 
233
                    [a-zA-Z_][a-zA-Z0-9_]*\s*=\s*
 
234
                    (?:
 
235
                        (?:".*?")|              # double quotes
 
236
                        (?:'.*?')|              # single quotes
 
237
                        (?:[^'",\s=][^,=]*?)       # unquoted
 
238
                    )
 
239
                )
 
240
            )
 
241
        )
 
242
        (?:
 
243
            (?:\s*,\s*)|(?:\s*$)            # comma
 
244
        )
 
245
    )
 
246
    '''
 
247
 
 
248
_matchstring = '^%s*' % _paramstring
 
249
 
162
250
# Python pre 2.2.1 doesn't have bool
163
251
try:
164
252
    bool
433
521
        http://www.voidspace.org.uk/python/configobj.html
434
522
    """
435
523
 
436
 
    # this regex pulls values out of a comma separated line
437
 
    _paramfinder = re.compile(r'''(?:'.*?')|(?:".*?")|(?:[^'",\s][^,]*)''')
438
 
    # this regex is used for finding keyword arguments
439
 
    _key_arg = re.compile(r'^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.*)$')
440
524
    # this regex does the initial parsing of the checks
441
525
    _func_re = re.compile(r'(.+?)\((.*)\)')
442
526
 
 
527
    # this regex takes apart keyword arguments
 
528
    _key_arg = re.compile(r'^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.*)$')
 
529
 
 
530
 
 
531
    # this regex finds keyword=list(....) type values
 
532
    _list_arg = _list_arg
 
533
 
 
534
    # this regex takes individual values out of lists - in one pass
 
535
    _list_members = _list_members
 
536
 
 
537
    # These regexes check a set of arguments for validity
 
538
    # and then pull the members out
 
539
    _paramfinder = re.compile(_paramstring, re.VERBOSE)
 
540
    _matchfinder = re.compile(_matchstring, re.VERBOSE)
 
541
 
 
542
 
443
543
    def __init__(self, functions=None):
444
544
        """
445
545
        >>> vtri = Validator()
487
587
        fun_match = self._func_re.match(check)
488
588
        if fun_match:
489
589
            fun_name = fun_match.group(1)
 
590
            arg_string = fun_match.group(2)
 
591
            arg_match = self._matchfinder.match(arg_string)
 
592
            if arg_match is None:
 
593
                # Bad syntax
 
594
                raise VdtParamError
490
595
            fun_args = []
491
596
            fun_kwargs = {}
492
597
            # pull out args of group 2
493
 
            for arg in self._paramfinder.findall(fun_match.group(2)):
 
598
            for arg in self._paramfinder.findall(arg_string):
494
599
                # args may need whitespace removing (before removing quotes)
495
600
                arg = arg.strip()
 
601
                listmatch = self._list_arg.match(arg)
 
602
                if listmatch:
 
603
                    key, val = self._list_handle(listmatch)
 
604
                    fun_kwargs[key] = val
 
605
                    continue
496
606
                keymatch = self._key_arg.match(arg)
497
607
                if keymatch:
498
 
                    val = keymatch.group(2)
499
 
                    if (val[0] in ("'", '"')) and (val[0] == val[-1]):
500
 
                        val = val[1:-1]
 
608
                    val = self._unquote(keymatch.group(2))
501
609
                    fun_kwargs[keymatch.group(1)] = val
502
610
                    continue
503
611
                #
504
 
                if (arg[0] in ("'", '"')) and (arg[0] == arg[-1]):
505
 
                    arg = arg[1:-1]
506
 
                fun_args.append(arg)
 
612
                fun_args.append(self._unquote(arg))
507
613
        else:
508
614
            # allows for function names without (args)
509
615
            (fun_name, fun_args, fun_kwargs) = (check, (), {})
524
630
        except KeyError:
525
631
            pass
526
632
        try:
527
 
            return self.functions[fun_name](value, *fun_args, **fun_kwargs)
 
633
            fun = self.functions[fun_name]
528
634
        except KeyError:
529
635
            raise VdtUnknownCheckError(fun_name)
 
636
        else:
 
637
##            print fun_args
 
638
##            print fun_kwargs
 
639
            return fun(value, *fun_args, **fun_kwargs)
 
640
 
 
641
    def _unquote(self, val):
 
642
        """Unquote a value if necessary."""
 
643
        if (len(val) > 2) and (val[0] in ("'", '"')) and (val[0] == val[-1]):
 
644
            val = val[1:-1]
 
645
        return val
 
646
 
 
647
    def _list_handle(self, listmatch):
 
648
        """Take apart a ``keyword=list('val, 'val')`` type string."""
 
649
        out = []
 
650
        name = listmatch.group(1)
 
651
        args = listmatch.group(2)
 
652
        for arg in self._list_members.findall(args):
 
653
            out.append(self._unquote(arg))
 
654
        return name, out
530
655
 
531
656
    def _pass(self, value):
532
657
        """
1059
1184
        raise VdtValueError(value)
1060
1185
    return value
1061
1186
 
 
1187
def _test(value, *args, **keywargs):
 
1188
    """
 
1189
    A function that exists for test purposes.
 
1190
    
 
1191
    >>> checks = [
 
1192
    ...     '3, 6, min=1, max=3, test=list(a, b, c)',
 
1193
    ...     '3',
 
1194
    ...     '3, 6',
 
1195
    ...     '3,',
 
1196
    ...     'min=1, test="a b c"',
 
1197
    ...     'min=5, test="a, b, c"',
 
1198
    ...     'min=1, max=3, test="a, b, c"',
 
1199
    ...     'min=-100, test=-99',
 
1200
    ...     'min=1, max=3',
 
1201
    ...     '3, 6, test="36"',
 
1202
    ...     '3, 6, test="a, b, c"',
 
1203
    ...     '3, max=3, test=list("a", "b", "c")',
 
1204
    ...     '''3, max=3, test=list("'a'", 'b', "x=(c)")''',
 
1205
    ...     "test='x=fish(3)'",
 
1206
    ...    ]
 
1207
    >>> v = Validator({'test': _test})
 
1208
    >>> for entry in checks:
 
1209
    ...     print v.check(('test(%s)' % entry), 3)
 
1210
    (3, ('3', '6'), {'test': ['a', 'b', 'c'], 'max': '3', 'min': '1'})
 
1211
    (3, ('3',), {})
 
1212
    (3, ('3', '6'), {})
 
1213
    (3, ('3',), {})
 
1214
    (3, (), {'test': 'a b c', 'min': '1'})
 
1215
    (3, (), {'test': 'a, b, c', 'min': '5'})
 
1216
    (3, (), {'test': 'a, b, c', 'max': '3', 'min': '1'})
 
1217
    (3, (), {'test': '-99', 'min': '-100'})
 
1218
    (3, (), {'max': '3', 'min': '1'})
 
1219
    (3, ('3', '6'), {'test': '36'})
 
1220
    (3, ('3', '6'), {'test': 'a, b, c'})
 
1221
    (3, ('3',), {'test': ['a', 'b', 'c'], 'max': '3'})
 
1222
    (3, ('3',), {'test': ["'a'", 'b', 'x=(c)'], 'max': '3'})
 
1223
    (3, (), {'test': 'x=fish(3)'})
 
1224
    """
 
1225
    return (value, args, keywargs)
 
1226
 
 
1227
 
1062
1228
if __name__ == '__main__':
1063
1229
    # run the code tests in doctest format
1064
1230
    import doctest
1081
1247
    ISSUES
1082
1248
    ======
1083
1249
    
1084
 
    Lists passed as function arguments need additional quotes. Ugly, could do
1085
 
    with fixing this.
1086
 
    
1087
1250
    If we could pull tuples out of arguments, it would be easier
1088
1251
    to specify arguments for 'mixed_lists'.
1089
1252
    
1090
1253
    CHANGELOG
1091
1254
    =========
1092
1255
    
 
1256
    2005/12/16
 
1257
    ----------
 
1258
    
 
1259
    Fixed bug so we can handle keyword argument values with commas.
 
1260
    
 
1261
    We now use a list constructor for passing list values to keyword arguments
 
1262
    (including ``default``) : ::
 
1263
    
 
1264
        default=list("val", "val", "val")
 
1265
    
 
1266
    Added the ``_test`` test. {sm;:-)}
 
1267
    
 
1268
    0.2.1
 
1269
    
 
1270
    2005/12/12
 
1271
    ----------
 
1272
    
 
1273
    Moved a function call outside a try...except block.
 
1274
    
1093
1275
    2005/08/25
1094
1276
    ----------
1095
1277