/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
# configobj.py
2
# A config file reader/writer that supports nested sections in config files.
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
3
# Copyright (C) 2005-2006 Michael Foord, Nicola Larosa
1185.12.49 by Aaron Bentley
Switched to ConfigObj
4
# E-mail: fuzzyman AT voidspace DOT org DOT uk
5
#         nico AT tekNico DOT net
6
7
# ConfigObj 4
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
8
# http://www.voidspace.org.uk/python/configobj.html
1185.12.49 by Aaron Bentley
Switched to ConfigObj
9
10
# Released subject to the BSD License
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
11
# Please see http://www.voidspace.org.uk/python/license.shtml
1185.12.49 by Aaron Bentley
Switched to ConfigObj
12
13
# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
14
# For information about bugfixes, updates and support, please join the
15
# ConfigObj mailing list:
16
# http://lists.sourceforge.net/lists/listinfo/configobj-develop
17
# Comments, suggestions and bug reports welcome.
18
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
19
from __future__ import generators
20
1185.12.49 by Aaron Bentley
Switched to ConfigObj
21
import sys
22
INTP_VER = sys.version_info[:2]
23
if INTP_VER < (2, 2):
24
    raise RuntimeError("Python v.2.2 or later needed")
25
26
import os, re
3224.5.1 by Andrew Bennetts
Lots of assorted hackery to reduce the number of imports for common operations. Improves 'rocks', 'st' and 'help' times by ~50ms on my laptop.
27
28
from bzrlib.lazy_import import lazy_import
29
lazy_import(globals(), """
30
import compiler
31
""")
32
1185.12.49 by Aaron Bentley
Switched to ConfigObj
33
from types import StringTypes
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
34
from warnings import warn
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
35
try:
36
    from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE
37
except ImportError:
38
    # Python 2.2 does not have these
39
    # UTF-8
40
    BOM_UTF8 = '\xef\xbb\xbf'
41
    # UTF-16, little endian
42
    BOM_UTF16_LE = '\xff\xfe'
43
    # UTF-16, big endian
44
    BOM_UTF16_BE = '\xfe\xff'
45
    if sys.byteorder == 'little':
46
        # UTF-16, native endianness
47
        BOM_UTF16 = BOM_UTF16_LE
48
    else:
49
        # UTF-16, native endianness
50
        BOM_UTF16 = BOM_UTF16_BE
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
51
52
# A dictionary mapping BOM to
53
# the encoding to decode with, and what to set the
54
# encoding attribute to.
55
BOMS = {
56
    BOM_UTF8: ('utf_8', None),
57
    BOM_UTF16_BE: ('utf16_be', 'utf_16'),
58
    BOM_UTF16_LE: ('utf16_le', 'utf_16'),
59
    BOM_UTF16: ('utf_16', 'utf_16'),
60
    }
61
# All legal variants of the BOM codecs.
62
# TODO: the list of aliases is not meant to be exhaustive, is there a
63
#   better way ?
64
BOM_LIST = {
65
    'utf_16': 'utf_16',
66
    'u16': 'utf_16',
67
    'utf16': 'utf_16',
68
    'utf-16': 'utf_16',
69
    'utf16_be': 'utf16_be',
70
    'utf_16_be': 'utf16_be',
71
    'utf-16be': 'utf16_be',
72
    'utf16_le': 'utf16_le',
73
    'utf_16_le': 'utf16_le',
74
    'utf-16le': 'utf16_le',
75
    'utf_8': 'utf_8',
76
    'u8': 'utf_8',
77
    'utf': 'utf_8',
78
    'utf8': 'utf_8',
79
    'utf-8': 'utf_8',
80
    }
81
82
# Map of encodings to the BOM to write.
83
BOM_SET = {
84
    'utf_8': BOM_UTF8,
85
    'utf_16': BOM_UTF16,
86
    'utf16_be': BOM_UTF16_BE,
87
    'utf16_le': BOM_UTF16_LE,
88
    None: BOM_UTF8
89
    }
90
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
91
__version__ = '4.4.0'
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
92
93
__revision__ = '$Id: configobj.py 156 2006-01-31 14:57:08Z fuzzyman $'
1185.12.49 by Aaron Bentley
Switched to ConfigObj
94
95
__docformat__ = "restructuredtext en"
96
97
__all__ = (
98
    '__version__',
99
    'DEFAULT_INDENT_TYPE',
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
100
    'DEFAULT_INTERPOLATION',
1185.12.49 by Aaron Bentley
Switched to ConfigObj
101
    'ConfigObjError',
102
    'NestingError',
103
    'ParseError',
104
    'DuplicateError',
105
    'ConfigspecError',
106
    'ConfigObj',
107
    'SimpleVal',
108
    'InterpolationError',
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
109
    'InterpolationLoopError',
1185.12.49 by Aaron Bentley
Switched to ConfigObj
110
    'MissingInterpolationOption',
111
    'RepeatSectionError',
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
112
    'UnreprError',
113
    'UnknownType',
1185.12.49 by Aaron Bentley
Switched to ConfigObj
114
    '__docformat__',
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
115
    'flatten_errors',
1185.12.49 by Aaron Bentley
Switched to ConfigObj
116
)
117
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
118
DEFAULT_INTERPOLATION = 'configparser'
119
DEFAULT_INDENT_TYPE = '    '
1185.12.49 by Aaron Bentley
Switched to ConfigObj
120
MAX_INTERPOL_DEPTH = 10
121
122
OPTION_DEFAULTS = {
123
    'interpolation': True,
124
    'raise_errors': False,
125
    'list_values': True,
126
    'create_empty': False,
127
    'file_error': False,
128
    'configspec': None,
129
    'stringify': True,
130
    # option may be set to one of ('', ' ', '\t')
131
    'indent_type': None,
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
132
    'encoding': None,
133
    'default_encoding': None,
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
134
    'unrepr': False,
135
    'write_empty_values': False,
1185.12.49 by Aaron Bentley
Switched to ConfigObj
136
}
137
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
138
139
def getObj(s):
140
    s = "a=" + s
141
    p = compiler.parse(s)
142
    return p.getChildren()[1].getChildren()[0].getChildren()[1]
143
144
class UnknownType(Exception):
145
    pass
146
147
class Builder:
148
    
149
    def build(self, o):
150
        m = getattr(self, 'build_' + o.__class__.__name__, None)
151
        if m is None:
152
            raise UnknownType(o.__class__.__name__)
153
        return m(o)
154
    
155
    def build_List(self, o):
156
        return map(self.build, o.getChildren())
157
    
158
    def build_Const(self, o):
159
        return o.value
160
    
161
    def build_Dict(self, o):
162
        d = {}
163
        i = iter(map(self.build, o.getChildren()))
164
        for el in i:
165
            d[el] = i.next()
166
        return d
167
    
168
    def build_Tuple(self, o):
169
        return tuple(self.build_List(o))
170
    
171
    def build_Name(self, o):
172
        if o.name == 'None':
173
            return None
174
        if o.name == 'True':
175
            return True
176
        if o.name == 'False':
177
            return False
178
        
179
        # An undefinted Name
180
        raise UnknownType('Undefined Name')
181
    
182
    def build_Add(self, o):
183
        real, imag = map(self.build_Const, o.getChildren())
184
        try:
185
            real = float(real)
186
        except TypeError:
187
            raise UnknownType('Add')
188
        if not isinstance(imag, complex) or imag.real != 0.0:
189
            raise UnknownType('Add')
190
        return real+imag
191
    
192
    def build_Getattr(self, o):
193
        parent = self.build(o.expr)
194
        return getattr(parent, o.attrname)
195
    
196
    def build_UnarySub(self, o):
197
        return -self.build_Const(o.getChildren()[0])
198
    
199
    def build_UnaryAdd(self, o):
200
        return self.build_Const(o.getChildren()[0])
201
202
def unrepr(s):
203
    if not s:
204
        return s
205
    return Builder().build(getObj(s))
206
207
def _splitlines(instring):
208
    """Split a string on lines, without losing line endings or truncating."""
209
    
210
1185.12.49 by Aaron Bentley
Switched to ConfigObj
211
class ConfigObjError(SyntaxError):
212
    """
213
    This is the base class for all errors that ConfigObj raises.
214
    It is a subclass of SyntaxError.
215
    """
216
    def __init__(self, message='', line_number=None, line=''):
217
        self.line = line
218
        self.line_number = line_number
219
        self.message = message
220
        SyntaxError.__init__(self, message)
221
222
class NestingError(ConfigObjError):
223
    """
224
    This error indicates a level of nesting that doesn't match.
225
    """
226
227
class ParseError(ConfigObjError):
228
    """
229
    This error indicates that a line is badly written.
230
    It is neither a valid ``key = value`` line,
231
    nor a valid section marker line.
232
    """
233
234
class DuplicateError(ConfigObjError):
235
    """
236
    The keyword or section specified already exists.
237
    """
238
239
class ConfigspecError(ConfigObjError):
240
    """
241
    An error occured whilst parsing a configspec.
242
    """
243
244
class InterpolationError(ConfigObjError):
245
    """Base class for the two interpolation errors."""
246
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
247
class InterpolationLoopError(InterpolationError):
1185.12.49 by Aaron Bentley
Switched to ConfigObj
248
    """Maximum interpolation depth exceeded in string interpolation."""
249
250
    def __init__(self, option):
251
        InterpolationError.__init__(
252
            self,
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
253
            'interpolation loop detected in value "%s".' % option)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
254
255
class RepeatSectionError(ConfigObjError):
256
    """
257
    This error indicates additional sections in a section with a
258
    ``__many__`` (repeated) section.
259
    """
260
261
class MissingInterpolationOption(InterpolationError):
262
    """A value specified for interpolation was missing."""
263
264
    def __init__(self, option):
265
        InterpolationError.__init__(
266
            self,
267
            'missing option "%s" in interpolation.' % option)
268
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
269
class UnreprError(ConfigObjError):
270
    """An error parsing in unrepr mode."""
271
272
273
class InterpolationEngine(object):
274
    """
275
    A helper class to help perform string interpolation.
276
277
    This class is an abstract base class; its descendants perform
278
    the actual work.
279
    """
280
281
    # compiled regexp to use in self.interpolate()
282
    _KEYCRE = re.compile(r"%\(([^)]*)\)s")
283
284
    def __init__(self, section):
285
        # the Section instance that "owns" this engine
286
        self.section = section
287
288
    def interpolate(self, key, value):
289
        def recursive_interpolate(key, value, section, backtrail):
290
            """The function that does the actual work.
291
292
            ``value``: the string we're trying to interpolate.
293
            ``section``: the section in which that string was found
294
            ``backtrail``: a dict to keep track of where we've been,
295
            to detect and prevent infinite recursion loops
296
297
            This is similar to a depth-first-search algorithm.
298
            """
299
            # Have we been here already?
300
            if backtrail.has_key((key, section.name)):
301
                # Yes - infinite loop detected
302
                raise InterpolationLoopError(key)
303
            # Place a marker on our backtrail so we won't come back here again
304
            backtrail[(key, section.name)] = 1
305
306
            # Now start the actual work
307
            match = self._KEYCRE.search(value)
308
            while match:
309
                # The actual parsing of the match is implementation-dependent,
310
                # so delegate to our helper function
311
                k, v, s = self._parse_match(match)
312
                if k is None:
313
                    # That's the signal that no further interpolation is needed
314
                    replacement = v
315
                else:
316
                    # Further interpolation may be needed to obtain final value
317
                    replacement = recursive_interpolate(k, v, s, backtrail)
318
                # Replace the matched string with its final value
319
                start, end = match.span()
320
                value = ''.join((value[:start], replacement, value[end:]))
321
                new_search_start = start + len(replacement)
322
                # Pick up the next interpolation key, if any, for next time
323
                # through the while loop
324
                match = self._KEYCRE.search(value, new_search_start)
325
326
            # Now safe to come back here again; remove marker from backtrail
327
            del backtrail[(key, section.name)]
328
329
            return value
330
331
        # Back in interpolate(), all we have to do is kick off the recursive
332
        # function with appropriate starting values
333
        value = recursive_interpolate(key, value, self.section, {})
334
        return value
335
336
    def _fetch(self, key):
337
        """Helper function to fetch values from owning section.
338
339
        Returns a 2-tuple: the value, and the section where it was found.
340
        """
341
        # switch off interpolation before we try and fetch anything !
342
        save_interp = self.section.main.interpolation
343
        self.section.main.interpolation = False
344
345
        # Start at section that "owns" this InterpolationEngine
346
        current_section = self.section
347
        while True:
348
            # try the current section first
349
            val = current_section.get(key)
350
            if val is not None:
351
                break
352
            # try "DEFAULT" next
353
            val = current_section.get('DEFAULT', {}).get(key)
354
            if val is not None:
355
                break
356
            # move up to parent and try again
357
            # top-level's parent is itself
358
            if current_section.parent is current_section:
359
                # reached top level, time to give up
360
                break
361
            current_section = current_section.parent
362
363
        # restore interpolation to previous value before returning
364
        self.section.main.interpolation = save_interp
365
        if val is None:
366
            raise MissingInterpolationOption(key)
367
        return val, current_section
368
369
    def _parse_match(self, match):
370
        """Implementation-dependent helper function.
371
372
        Will be passed a match object corresponding to the interpolation
373
        key we just found (e.g., "%(foo)s" or "$foo"). Should look up that
374
        key in the appropriate config file section (using the ``_fetch()``
375
        helper function) and return a 3-tuple: (key, value, section)
376
377
        ``key`` is the name of the key we're looking for
378
        ``value`` is the value found for that key
379
        ``section`` is a reference to the section where it was found
380
381
        ``key`` and ``section`` should be None if no further
382
        interpolation should be performed on the resulting value
383
        (e.g., if we interpolated "$$" and returned "$").
384
        """
385
        raise NotImplementedError
386
    
387
388
class ConfigParserInterpolation(InterpolationEngine):
389
    """Behaves like ConfigParser."""
390
    _KEYCRE = re.compile(r"%\(([^)]*)\)s")
391
392
    def _parse_match(self, match):
393
        key = match.group(1)
394
        value, section = self._fetch(key)
395
        return key, value, section
396
397
398
class TemplateInterpolation(InterpolationEngine):
399
    """Behaves like string.Template."""
400
    _delimiter = '$'
401
    _KEYCRE = re.compile(r"""
402
        \$(?:
403
          (?P<escaped>\$)              |   # Two $ signs
404
          (?P<named>[_a-z][_a-z0-9]*)  |   # $name format
405
          {(?P<braced>[^}]*)}              # ${name} format
406
        )
407
        """, re.IGNORECASE | re.VERBOSE)
408
409
    def _parse_match(self, match):
410
        # Valid name (in or out of braces): fetch value from section
411
        key = match.group('named') or match.group('braced')
412
        if key is not None:
413
            value, section = self._fetch(key)
414
            return key, value, section
415
        # Escaped delimiter (e.g., $$): return single delimiter
416
        if match.group('escaped') is not None:
417
            # Return None for key and section to indicate it's time to stop
418
            return None, self._delimiter, None
419
        # Anything else: ignore completely, just return it unchanged
420
        return None, match.group(), None
421
422
interpolation_engines = {
423
    'configparser': ConfigParserInterpolation,
424
    'template': TemplateInterpolation,
425
}
426
1185.12.49 by Aaron Bentley
Switched to ConfigObj
427
class Section(dict):
428
    """
429
    A dictionary-like object that represents a section in a config file.
430
    
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
431
    It does string interpolation if the 'interpolation' attribute
1185.12.49 by Aaron Bentley
Switched to ConfigObj
432
    of the 'main' object is set to True.
433
    
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
434
    Interpolation is tried first from this object, then from the 'DEFAULT'
435
    section of this object, next from the parent and its 'DEFAULT' section,
436
    and so on until the main object is reached.
1185.12.49 by Aaron Bentley
Switched to ConfigObj
437
    
438
    A Section will behave like an ordered dictionary - following the
439
    order of the ``scalars`` and ``sections`` attributes.
440
    You can use this to change the order of members.
441
    
442
    Iteration follows the order: scalars, then sections.
443
    """
444
445
    def __init__(self, parent, depth, main, indict=None, name=None):
446
        """
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
447
        * parent is the section above
448
        * depth is the depth level of this section
449
        * main is the main ConfigObj
450
        * indict is a dictionary to initialise the section with
1185.12.49 by Aaron Bentley
Switched to ConfigObj
451
        """
452
        if indict is None:
453
            indict = {}
454
        dict.__init__(self)
455
        # used for nesting level *and* interpolation
456
        self.parent = parent
457
        # used for the interpolation attribute
458
        self.main = main
459
        # level of nesting depth of this Section
460
        self.depth = depth
461
        # the sequence of scalar values in this Section
462
        self.scalars = []
463
        # the sequence of sections in this Section
464
        self.sections = []
465
        # purely for information
466
        self.name = name
467
        # for comments :-)
468
        self.comments = {}
469
        self.inline_comments = {}
470
        # for the configspec
471
        self.configspec = {}
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
472
        self._order = []
473
        self._configspec_comments = {}
474
        self._configspec_inline_comments = {}
475
        self._cs_section_comments = {}
476
        self._cs_section_inline_comments = {}
1185.12.49 by Aaron Bentley
Switched to ConfigObj
477
        # for defaults
478
        self.defaults = []
479
        #
480
        # we do this explicitly so that __setitem__ is used properly
481
        # (rather than just passing to ``dict.__init__``)
482
        for entry in indict:
483
            self[entry] = indict[entry]
484
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
485
    def _interpolate(self, key, value):
486
        try:
487
            # do we already have an interpolation engine?
488
            engine = self._interpolation_engine
489
        except AttributeError:
490
            # not yet: first time running _interpolate(), so pick the engine
491
            name = self.main.interpolation
492
            if name == True:  # note that "if name:" would be incorrect here
493
                # backwards-compatibility: interpolation=True means use default
494
                name = DEFAULT_INTERPOLATION
495
            name = name.lower()  # so that "Template", "template", etc. all work
496
            class_ = interpolation_engines.get(name, None)
497
            if class_ is None:
498
                # invalid value for self.main.interpolation
499
                self.main.interpolation = False
500
                return value
1185.12.49 by Aaron Bentley
Switched to ConfigObj
501
            else:
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
502
                # save reference to engine so we don't have to do this again
503
                engine = self._interpolation_engine = class_(self)
504
        # let the engine do the actual work
505
        return engine.interpolate(key, value)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
506
507
    def __getitem__(self, key):
508
        """Fetch the item and do string interpolation."""
509
        val = dict.__getitem__(self, key)
510
        if self.main.interpolation and isinstance(val, StringTypes):
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
511
            return self._interpolate(key, val)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
512
        return val
513
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
514
    def __setitem__(self, key, value, unrepr=False):
1185.12.49 by Aaron Bentley
Switched to ConfigObj
515
        """
516
        Correctly set a value.
517
        
518
        Making dictionary values Section instances.
519
        (We have to special case 'Section' instances - which are also dicts)
520
        
521
        Keys must be strings.
522
        Values need only be strings (or lists of strings) if
523
        ``main.stringify`` is set.
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
524
        
525
        `unrepr`` must be set when setting a value to a dictionary, without
526
        creating a new sub-section.
1185.12.49 by Aaron Bentley
Switched to ConfigObj
527
        """
528
        if not isinstance(key, StringTypes):
529
            raise ValueError, 'The key "%s" is not a string.' % key
530
        # add the comment
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
531
        if not self.comments.has_key(key):
1185.12.49 by Aaron Bentley
Switched to ConfigObj
532
            self.comments[key] = []
533
            self.inline_comments[key] = ''
534
        # remove the entry from defaults
535
        if key in self.defaults:
536
            self.defaults.remove(key)
537
        #
538
        if isinstance(value, Section):
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
539
            if not self.has_key(key):
1185.12.49 by Aaron Bentley
Switched to ConfigObj
540
                self.sections.append(key)
541
            dict.__setitem__(self, key, value)
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
542
        elif isinstance(value, dict) and not unrepr:
1185.12.49 by Aaron Bentley
Switched to ConfigObj
543
            # First create the new depth level,
544
            # then create the section
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
545
            if not self.has_key(key):
1185.12.49 by Aaron Bentley
Switched to ConfigObj
546
                self.sections.append(key)
547
            new_depth = self.depth + 1
548
            dict.__setitem__(
549
                self,
550
                key,
551
                Section(
552
                    self,
553
                    new_depth,
554
                    self.main,
555
                    indict=value,
556
                    name=key))
557
        else:
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
558
            if not self.has_key(key):
1185.12.49 by Aaron Bentley
Switched to ConfigObj
559
                self.scalars.append(key)
560
            if not self.main.stringify:
561
                if isinstance(value, StringTypes):
562
                    pass
563
                elif isinstance(value, (list, tuple)):
564
                    for entry in value:
565
                        if not isinstance(entry, StringTypes):
566
                            raise TypeError, (
567
                                'Value is not a string "%s".' % entry)
568
                else:
569
                    raise TypeError, 'Value is not a string "%s".' % value
570
            dict.__setitem__(self, key, value)
571
572
    def __delitem__(self, key):
573
        """Remove items from the sequence when deleting."""
574
        dict. __delitem__(self, key)
575
        if key in self.scalars:
576
            self.scalars.remove(key)
577
        else:
578
            self.sections.remove(key)
579
        del self.comments[key]
580
        del self.inline_comments[key]
581
582
    def get(self, key, default=None):
583
        """A version of ``get`` that doesn't bypass string interpolation."""
584
        try:
585
            return self[key]
586
        except KeyError:
587
            return default
588
589
    def update(self, indict):
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
590
        """
591
        A version of update that uses our ``__setitem__``.
592
        """
1185.12.49 by Aaron Bentley
Switched to ConfigObj
593
        for entry in indict:
594
            self[entry] = indict[entry]
595
596
    def pop(self, key, *args):
597
        """ """
598
        val = dict.pop(self, key, *args)
599
        if key in self.scalars:
600
            del self.comments[key]
601
            del self.inline_comments[key]
602
            self.scalars.remove(key)
603
        elif key in self.sections:
604
            del self.comments[key]
605
            del self.inline_comments[key]
606
            self.sections.remove(key)
607
        if self.main.interpolation and isinstance(val, StringTypes):
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
608
            return self._interpolate(key, val)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
609
        return val
610
611
    def popitem(self):
612
        """Pops the first (key,val)"""
613
        sequence = (self.scalars + self.sections)
614
        if not sequence:
615
            raise KeyError, ": 'popitem(): dictionary is empty'"
616
        key = sequence[0]
617
        val =  self[key]
618
        del self[key]
619
        return key, val
620
621
    def clear(self):
622
        """
623
        A version of clear that also affects scalars/sections
624
        Also clears comments and configspec.
625
        
626
        Leaves other attributes alone :
627
            depth/main/parent are not affected
628
        """
629
        dict.clear(self)
630
        self.scalars = []
631
        self.sections = []
632
        self.comments = {}
633
        self.inline_comments = {}
634
        self.configspec = {}
635
636
    def setdefault(self, key, default=None):
637
        """A version of setdefault that sets sequence if appropriate."""
638
        try:
639
            return self[key]
640
        except KeyError:
641
            self[key] = default
642
            return self[key]
643
644
    def items(self):
645
        """ """
646
        return zip((self.scalars + self.sections), self.values())
647
648
    def keys(self):
649
        """ """
650
        return (self.scalars + self.sections)
651
652
    def values(self):
653
        """ """
654
        return [self[key] for key in (self.scalars + self.sections)]
655
656
    def iteritems(self):
657
        """ """
658
        return iter(self.items())
659
660
    def iterkeys(self):
661
        """ """
662
        return iter((self.scalars + self.sections))
663
664
    __iter__ = iterkeys
665
666
    def itervalues(self):
667
        """ """
668
        return iter(self.values())
669
670
    def __repr__(self):
671
        return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(self[key])))
672
            for key in (self.scalars + self.sections)])
673
674
    __str__ = __repr__
675
676
    # Extra methods - not in a normal dictionary
677
678
    def dict(self):
679
        """
680
        Return a deepcopy of self as a dictionary.
681
        
682
        All members that are ``Section`` instances are recursively turned to
683
        ordinary dictionaries - by calling their ``dict`` method.
684
        
685
        >>> n = a.dict()
686
        >>> n == a
687
        1
688
        >>> n is a
689
        0
690
        """
691
        newdict = {}
692
        for entry in self:
693
            this_entry = self[entry]
694
            if isinstance(this_entry, Section):
695
                this_entry = this_entry.dict()
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
696
            elif isinstance(this_entry, list):
1185.12.49 by Aaron Bentley
Switched to ConfigObj
697
                # create a copy rather than a reference
698
                this_entry = list(this_entry)
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
699
            elif isinstance(this_entry, tuple):
700
                # create a copy rather than a reference
701
                this_entry = tuple(this_entry)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
702
            newdict[entry] = this_entry
703
        return newdict
704
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
705
    def merge(self, indict):
706
        """
707
        A recursive update - useful for merging config files.
708
        
709
        >>> a = '''[section1]
710
        ...     option1 = True
711
        ...     [[subsection]]
712
        ...     more_options = False
713
        ...     # end of file'''.splitlines()
714
        >>> b = '''# File is user.ini
715
        ...     [section1]
716
        ...     option1 = False
717
        ...     # end of file'''.splitlines()
718
        >>> c1 = ConfigObj(b)
719
        >>> c2 = ConfigObj(a)
720
        >>> c2.merge(c1)
721
        >>> c2
722
        {'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}}
723
        """
724
        for key, val in indict.items():
725
            if (key in self and isinstance(self[key], dict) and
726
                                isinstance(val, dict)):
727
                self[key].merge(val)
728
            else:   
729
                self[key] = val
730
1185.12.49 by Aaron Bentley
Switched to ConfigObj
731
    def rename(self, oldkey, newkey):
732
        """
733
        Change a keyname to another, without changing position in sequence.
734
        
735
        Implemented so that transformations can be made on keys,
736
        as well as on values. (used by encode and decode)
737
        
738
        Also renames comments.
739
        """
740
        if oldkey in self.scalars:
741
            the_list = self.scalars
742
        elif oldkey in self.sections:
743
            the_list = self.sections
744
        else:
745
            raise KeyError, 'Key "%s" not found.' % oldkey
746
        pos = the_list.index(oldkey)
747
        #
748
        val = self[oldkey]
749
        dict.__delitem__(self, oldkey)
750
        dict.__setitem__(self, newkey, val)
751
        the_list.remove(oldkey)
752
        the_list.insert(pos, newkey)
753
        comm = self.comments[oldkey]
754
        inline_comment = self.inline_comments[oldkey]
755
        del self.comments[oldkey]
756
        del self.inline_comments[oldkey]
757
        self.comments[newkey] = comm
758
        self.inline_comments[newkey] = inline_comment
759
760
    def walk(self, function, raise_errors=True,
761
            call_on_sections=False, **keywargs):
762
        """
763
        Walk every member and call a function on the keyword and value.
764
        
765
        Return a dictionary of the return values
766
        
767
        If the function raises an exception, raise the errror
768
        unless ``raise_errors=False``, in which case set the return value to
769
        ``False``.
770
        
771
        Any unrecognised keyword arguments you pass to walk, will be pased on
772
        to the function you pass in.
773
        
774
        Note: if ``call_on_sections`` is ``True`` then - on encountering a
775
        subsection, *first* the function is called for the *whole* subsection,
776
        and then recurses into it's members. This means your function must be
777
        able to handle strings, dictionaries and lists. This allows you
778
        to change the key of subsections as well as for ordinary members. The
779
        return value when called on the whole subsection has to be discarded.
780
        
781
        See  the encode and decode methods for examples, including functions.
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
782
        
783
        .. caution::
784
        
785
            You can use ``walk`` to transform the names of members of a section
786
            but you mustn't add or delete members.
787
        
788
        >>> config = '''[XXXXsection]
789
        ... XXXXkey = XXXXvalue'''.splitlines()
790
        >>> cfg = ConfigObj(config)
791
        >>> cfg
792
        {'XXXXsection': {'XXXXkey': 'XXXXvalue'}}
793
        >>> def transform(section, key):
794
        ...     val = section[key]
795
        ...     newkey = key.replace('XXXX', 'CLIENT1')
796
        ...     section.rename(key, newkey)
797
        ...     if isinstance(val, (tuple, list, dict)):
798
        ...         pass
799
        ...     else:
800
        ...         val = val.replace('XXXX', 'CLIENT1')
801
        ...         section[newkey] = val
802
        >>> cfg.walk(transform, call_on_sections=True)
803
        {'CLIENT1section': {'CLIENT1key': None}}
804
        >>> cfg
805
        {'CLIENT1section': {'CLIENT1key': 'CLIENT1value'}}
1185.12.49 by Aaron Bentley
Switched to ConfigObj
806
        """
807
        out = {}
808
        # scalars first
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
809
        for i in range(len(self.scalars)):
810
            entry = self.scalars[i]
1185.12.49 by Aaron Bentley
Switched to ConfigObj
811
            try:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
812
                val = function(self, entry, **keywargs)
813
                # bound again in case name has changed
814
                entry = self.scalars[i]
815
                out[entry] = val
1185.12.49 by Aaron Bentley
Switched to ConfigObj
816
            except Exception:
817
                if raise_errors:
818
                    raise
819
                else:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
820
                    entry = self.scalars[i]
1185.12.49 by Aaron Bentley
Switched to ConfigObj
821
                    out[entry] = False
822
        # then sections
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
823
        for i in range(len(self.sections)):
824
            entry = self.sections[i]
1185.12.49 by Aaron Bentley
Switched to ConfigObj
825
            if call_on_sections:
826
                try:
827
                    function(self, entry, **keywargs)
828
                except Exception:
829
                    if raise_errors:
830
                        raise
831
                    else:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
832
                        entry = self.sections[i]
1185.12.49 by Aaron Bentley
Switched to ConfigObj
833
                        out[entry] = False
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
834
                # bound again in case name has changed
835
                entry = self.sections[i]
1185.12.49 by Aaron Bentley
Switched to ConfigObj
836
            # previous result is discarded
837
            out[entry] = self[entry].walk(
838
                function,
839
                raise_errors=raise_errors,
840
                call_on_sections=call_on_sections,
841
                **keywargs)
842
        return out
843
844
    def decode(self, encoding):
845
        """
846
        Decode all strings and values to unicode, using the specified encoding.
847
        
848
        Works with subsections and list values.
849
        
850
        Uses the ``walk`` method.
851
        
852
        Testing ``encode`` and ``decode``.
853
        >>> m = ConfigObj(a)
854
        >>> m.decode('ascii')
855
        >>> def testuni(val):
856
        ...     for entry in val:
857
        ...         if not isinstance(entry, unicode):
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
858
        ...             print >> sys.stderr, type(entry)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
859
        ...             raise AssertionError, 'decode failed.'
860
        ...         if isinstance(val[entry], dict):
861
        ...             testuni(val[entry])
862
        ...         elif not isinstance(val[entry], unicode):
863
        ...             raise AssertionError, 'decode failed.'
864
        >>> testuni(m)
865
        >>> m.encode('ascii')
866
        >>> a == m
867
        1
868
        """
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
869
        warn('use of ``decode`` is deprecated.', DeprecationWarning)
870
        def decode(section, key, encoding=encoding, warn=True):
1185.12.49 by Aaron Bentley
Switched to ConfigObj
871
            """ """
872
            val = section[key]
873
            if isinstance(val, (list, tuple)):
874
                newval = []
875
                for entry in val:
876
                    newval.append(entry.decode(encoding))
877
            elif isinstance(val, dict):
878
                newval = val
879
            else:
880
                newval = val.decode(encoding)
881
            newkey = key.decode(encoding)
882
            section.rename(key, newkey)
883
            section[newkey] = newval
884
        # using ``call_on_sections`` allows us to modify section names
885
        self.walk(decode, call_on_sections=True)
886
887
    def encode(self, encoding):
888
        """
889
        Encode all strings and values from unicode,
890
        using the specified encoding.
891
        
892
        Works with subsections and list values.
893
        Uses the ``walk`` method.
894
        """
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
895
        warn('use of ``encode`` is deprecated.', DeprecationWarning)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
896
        def encode(section, key, encoding=encoding):
897
            """ """
898
            val = section[key]
899
            if isinstance(val, (list, tuple)):
900
                newval = []
901
                for entry in val:
902
                    newval.append(entry.encode(encoding))
903
            elif isinstance(val, dict):
904
                newval = val
905
            else:
906
                newval = val.encode(encoding)
907
            newkey = key.encode(encoding)
908
            section.rename(key, newkey)
909
            section[newkey] = newval
910
        self.walk(encode, call_on_sections=True)
911
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
912
    def istrue(self, key):
913
        """A deprecated version of ``as_bool``."""
914
        warn('use of ``istrue`` is deprecated. Use ``as_bool`` method '
915
                'instead.', DeprecationWarning)
916
        return self.as_bool(key)
917
918
    def as_bool(self, key):
919
        """
920
        Accepts a key as input. The corresponding value must be a string or
921
        the objects (``True`` or 1) or (``False`` or 0). We allow 0 and 1 to
922
        retain compatibility with Python 2.2.
923
        
924
        If the string is one of  ``True``, ``On``, ``Yes``, or ``1`` it returns 
925
        ``True``.
926
        
927
        If the string is one of  ``False``, ``Off``, ``No``, or ``0`` it returns 
928
        ``False``.
929
        
930
        ``as_bool`` is not case sensitive.
931
        
932
        Any other input will raise a ``ValueError``.
933
        
934
        >>> a = ConfigObj()
935
        >>> a['a'] = 'fish'
936
        >>> a.as_bool('a')
937
        Traceback (most recent call last):
938
        ValueError: Value "fish" is neither True nor False
939
        >>> a['b'] = 'True'
940
        >>> a.as_bool('b')
941
        1
942
        >>> a['b'] = 'off'
943
        >>> a.as_bool('b')
944
        0
945
        """
946
        val = self[key]
947
        if val == True:
948
            return True
949
        elif val == False:
950
            return False
951
        else:
952
            try:
953
                if not isinstance(val, StringTypes):
954
                    raise KeyError
955
                else:
956
                    return self.main._bools[val.lower()]
957
            except KeyError:
958
                raise ValueError('Value "%s" is neither True nor False' % val)
959
960
    def as_int(self, key):
961
        """
962
        A convenience method which coerces the specified value to an integer.
963
        
964
        If the value is an invalid literal for ``int``, a ``ValueError`` will
965
        be raised.
966
        
967
        >>> a = ConfigObj()
968
        >>> a['a'] = 'fish'
969
        >>> a.as_int('a')
970
        Traceback (most recent call last):
971
        ValueError: invalid literal for int(): fish
972
        >>> a['b'] = '1'
973
        >>> a.as_int('b')
974
        1
975
        >>> a['b'] = '3.2'
976
        >>> a.as_int('b')
977
        Traceback (most recent call last):
978
        ValueError: invalid literal for int(): 3.2
979
        """
980
        return int(self[key])
981
982
    def as_float(self, key):
983
        """
984
        A convenience method which coerces the specified value to a float.
985
        
986
        If the value is an invalid literal for ``float``, a ``ValueError`` will
987
        be raised.
988
        
989
        >>> a = ConfigObj()
990
        >>> a['a'] = 'fish'
991
        >>> a.as_float('a')
992
        Traceback (most recent call last):
993
        ValueError: invalid literal for float(): fish
994
        >>> a['b'] = '1'
995
        >>> a.as_float('b')
996
        1.0
997
        >>> a['b'] = '3.2'
998
        >>> a.as_float('b')
999
        3.2000000000000002
1000
        """
1001
        return float(self[key])
1002
    
1003
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1004
class ConfigObj(Section):
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1005
    """An object to read, create, and write config files."""
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1006
1007
    _keyword = re.compile(r'''^ # line start
1008
        (\s*)                   # indentation
1009
        (                       # keyword
1010
            (?:".*?")|          # double quotes
1011
            (?:'.*?')|          # single quotes
1012
            (?:[^'"=].*?)       # no quotes
1013
        )
1014
        \s*=\s*                 # divider
1015
        (.*)                    # value (including list values and comments)
1016
        $   # line end
1017
        ''',
1018
        re.VERBOSE)
1019
1020
    _sectionmarker = re.compile(r'''^
1021
        (\s*)                     # 1: indentation
1022
        ((?:\[\s*)+)              # 2: section marker open
1023
        (                         # 3: section name open
1024
            (?:"\s*\S.*?\s*")|    # at least one non-space with double quotes
1025
            (?:'\s*\S.*?\s*')|    # at least one non-space with single quotes
1026
            (?:[^'"\s].*?)        # at least one non-space unquoted
1027
        )                         # section name close
1028
        ((?:\s*\])+)              # 4: section marker close
1029
        \s*(\#.*)?                # 5: optional comment
1030
        $''',
1031
        re.VERBOSE)
1032
1033
    # this regexp pulls list values out as a single string
1034
    # or single values and comments
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1035
    # FIXME: this regex adds a '' to the end of comma terminated lists
1036
    #   workaround in ``_handle_value``
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1037
    _valueexp = re.compile(r'''^
1038
        (?:
1039
            (?:
1040
                (
1041
                    (?:
1042
                        (?:
1043
                            (?:".*?")|              # double quotes
1044
                            (?:'.*?')|              # single quotes
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1045
                            (?:[^'",\#][^,\#]*?)    # unquoted
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1046
                        )
1047
                        \s*,\s*                     # comma
1048
                    )*      # match all list items ending in a comma (if any)
1049
                )
1050
                (
1051
                    (?:".*?")|                      # double quotes
1052
                    (?:'.*?')|                      # single quotes
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1053
                    (?:[^'",\#\s][^,]*?)|           # unquoted
1054
                    (?:(?<!,))                      # Empty value
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1055
                )?          # last item in a list - or string value
1056
            )|
1057
            (,)             # alternatively a single comma - empty list
1058
        )
1059
        \s*(\#.*)?          # optional comment
1060
        $''',
1061
        re.VERBOSE)
1062
1063
    # use findall to get the members of a list value
1064
    _listvalueexp = re.compile(r'''
1065
        (
1066
            (?:".*?")|          # double quotes
1067
            (?:'.*?')|          # single quotes
1068
            (?:[^'",\#].*?)       # unquoted
1069
        )
1070
        \s*,\s*                 # comma
1071
        ''',
1072
        re.VERBOSE)
1073
1074
    # this regexp is used for the value
1075
    # when lists are switched off
1076
    _nolistvalue = re.compile(r'''^
1077
        (
1078
            (?:".*?")|          # double quotes
1079
            (?:'.*?')|          # single quotes
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1080
            (?:[^'"\#].*?)|     # unquoted
1081
            (?:)                # Empty value
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1082
        )
1083
        \s*(\#.*)?              # optional comment
1084
        $''',
1085
        re.VERBOSE)
1086
1087
    # regexes for finding triple quoted values on one line
1088
    _single_line_single = re.compile(r"^'''(.*?)'''\s*(#.*)?$")
1089
    _single_line_double = re.compile(r'^"""(.*?)"""\s*(#.*)?$')
1090
    _multi_line_single = re.compile(r"^(.*?)'''\s*(#.*)?$")
1091
    _multi_line_double = re.compile(r'^(.*?)"""\s*(#.*)?$')
1092
1093
    _triple_quote = {
1094
        "'''": (_single_line_single, _multi_line_single),
1095
        '"""': (_single_line_double, _multi_line_double),
1096
    }
1097
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1098
    # Used by the ``istrue`` Section method
1099
    _bools = {
1100
        'yes': True, 'no': False,
1101
        'on': True, 'off': False,
1102
        '1': True, '0': False,
1103
        'true': True, 'false': False,
1104
        }
1105
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1106
    def __init__(self, infile=None, options=None, **kwargs):
1107
        """
1108
        Parse or create a config file object.
1109
        
1110
        ``ConfigObj(infile=None, options=None, **kwargs)``
1111
        """
1112
        if infile is None:
1113
            infile = []
1114
        if options is None:
1115
            options = {}
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1116
        else:
1117
            options = dict(options)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1118
        # keyword arguments take precedence over an options dictionary
1119
        options.update(kwargs)
1120
        # init the superclass
1121
        Section.__init__(self, self, 0, self)
1122
        #
1123
        defaults = OPTION_DEFAULTS.copy()
1124
        for entry in options.keys():
1125
            if entry not in defaults.keys():
1126
                raise TypeError, 'Unrecognised option "%s".' % entry
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1127
        # TODO: check the values too.
1128
        #
1129
        # Add any explicit options to the defaults
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1130
        defaults.update(options)
1131
        #
1132
        # initialise a few variables
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1133
        self.filename = None
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1134
        self._errors = []
1135
        self.raise_errors = defaults['raise_errors']
1136
        self.interpolation = defaults['interpolation']
1137
        self.list_values = defaults['list_values']
1138
        self.create_empty = defaults['create_empty']
1139
        self.file_error = defaults['file_error']
1140
        self.stringify = defaults['stringify']
1141
        self.indent_type = defaults['indent_type']
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1142
        self.encoding = defaults['encoding']
1143
        self.default_encoding = defaults['default_encoding']
1144
        self.BOM = False
1145
        self.newlines = None
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1146
        self.write_empty_values = defaults['write_empty_values']
1147
        self.unrepr = defaults['unrepr']
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1148
        #
1149
        self.initial_comment = []
1150
        self.final_comment = []
1151
        #
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1152
        self._terminated = False
1153
        #
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1154
        if isinstance(infile, StringTypes):
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1155
            self.filename = infile
1156
            if os.path.isfile(infile):
1157
                infile = open(infile).read() or []
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1158
            elif self.file_error:
1159
                # raise an error if the file doesn't exist
1160
                raise IOError, 'Config file not found: "%s".' % self.filename
1161
            else:
1162
                # file doesn't already exist
1163
                if self.create_empty:
1164
                    # this is a good test that the filename specified
1165
                    # isn't impossible - like on a non existent device
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1166
                    h = open(infile, 'w')
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1167
                    h.write('')
1168
                    h.close()
1169
                infile = []
1170
        elif isinstance(infile, (list, tuple)):
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1171
            infile = list(infile)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1172
        elif isinstance(infile, dict):
1173
            # initialise self
1174
            # the Section class handles creating subsections
1175
            if isinstance(infile, ConfigObj):
1176
                # get a copy of our ConfigObj
1177
                infile = infile.dict()
1178
            for entry in infile:
1179
                self[entry] = infile[entry]
1180
            del self._errors
1181
            if defaults['configspec'] is not None:
1182
                self._handle_configspec(defaults['configspec'])
1183
            else:
1184
                self.configspec = None
1185
            return
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1186
        elif hasattr(infile, 'read'):
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1187
            # This supports file like objects
1188
            infile = infile.read() or []
1189
            # needs splitting into lines - but needs doing *after* decoding
1190
            # in case it's not an 8 bit encoding
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1191
        else:
1192
            raise TypeError, ('infile must be a filename,'
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1193
                ' file like object, or list of lines.')
1194
        #
1195
        if infile:
1196
            # don't do it for the empty ConfigObj
1197
            infile = self._handle_bom(infile)
1198
            # infile is now *always* a list
1199
            #
1200
            # Set the newlines attribute (first line ending it finds)
1201
            # and strip trailing '\n' or '\r' from lines
1202
            for line in infile:
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1203
                if (not line) or (line[-1] not in ('\r', '\n', '\r\n')):
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1204
                    continue
1205
                for end in ('\r\n', '\n', '\r'):
1206
                    if line.endswith(end):
1207
                        self.newlines = end
1208
                        break
1209
                break
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1210
            if infile[-1] and infile[-1] in ('\r', '\n', '\r\n'):
1211
                self._terminated = True
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1212
            infile = [line.rstrip('\r\n') for line in infile]
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1213
        #
1214
        self._parse(infile)
1215
        # if we had any errors, now is the time to raise them
1216
        if self._errors:
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1217
            info = "at line %s." % self._errors[0].line_number
1218
            if len(self._errors) > 1:
1219
                msg = ("Parsing failed with several errors.\nFirst error %s" %
1220
                    info)
1221
                error = ConfigObjError(msg)
1222
            else:
1223
                error = self._errors[0]
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1224
            # set the errors attribute; it's a list of tuples:
1225
            # (error_type, message, line_number)
1226
            error.errors = self._errors
1227
            # set the config attribute
1228
            error.config = self
1229
            raise error
1230
        # delete private attributes
1231
        del self._errors
1232
        #
1233
        if defaults['configspec'] is None:
1234
            self.configspec = None
1235
        else:
1236
            self._handle_configspec(defaults['configspec'])
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1237
    
1238
    def __repr__(self):
1239
        return 'ConfigObj({%s})' % ', '.join(
1240
            [('%s: %s' % (repr(key), repr(self[key]))) for key in
1241
            (self.scalars + self.sections)])
1242
    
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1243
    def _handle_bom(self, infile):
1244
        """
1245
        Handle any BOM, and decode if necessary.
1246
        
1247
        If an encoding is specified, that *must* be used - but the BOM should
1248
        still be removed (and the BOM attribute set).
1249
        
1250
        (If the encoding is wrongly specified, then a BOM for an alternative
1251
        encoding won't be discovered or removed.)
1252
        
1253
        If an encoding is not specified, UTF8 or UTF16 BOM will be detected and
1254
        removed. The BOM attribute will be set. UTF16 will be decoded to
1255
        unicode.
1256
        
1257
        NOTE: This method must not be called with an empty ``infile``.
1258
        
1259
        Specifying the *wrong* encoding is likely to cause a
1260
        ``UnicodeDecodeError``.
1261
        
1262
        ``infile`` must always be returned as a list of lines, but may be
1263
        passed in as a single string.
1264
        """
1265
        if ((self.encoding is not None) and
1266
            (self.encoding.lower() not in BOM_LIST)):
1267
            # No need to check for a BOM
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1268
            # the encoding specified doesn't have one
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1269
            # just decode
1270
            return self._decode(infile, self.encoding)
1271
        #
1272
        if isinstance(infile, (list, tuple)):
1273
            line = infile[0]
1274
        else:
1275
            line = infile
1276
        if self.encoding is not None:
1277
            # encoding explicitly supplied
1278
            # And it could have an associated BOM
1279
            # TODO: if encoding is just UTF16 - we ought to check for both
1280
            # TODO: big endian and little endian versions.
1281
            enc = BOM_LIST[self.encoding.lower()]
1282
            if enc == 'utf_16':
1283
                # For UTF16 we try big endian and little endian
1284
                for BOM, (encoding, final_encoding) in BOMS.items():
1285
                    if not final_encoding:
1286
                        # skip UTF8
1287
                        continue
1288
                    if infile.startswith(BOM):
1289
                        ### BOM discovered
1290
                        ##self.BOM = True
1291
                        # Don't need to remove BOM
1292
                        return self._decode(infile, encoding)
1293
                #
1294
                # If we get this far, will *probably* raise a DecodeError
1295
                # As it doesn't appear to start with a BOM
1296
                return self._decode(infile, self.encoding)
1297
            #
1298
            # Must be UTF8
1299
            BOM = BOM_SET[enc]
1300
            if not line.startswith(BOM):
1301
                return self._decode(infile, self.encoding)
1302
            #
1303
            newline = line[len(BOM):]
1304
            #
1305
            # BOM removed
1306
            if isinstance(infile, (list, tuple)):
1307
                infile[0] = newline
1308
            else:
1309
                infile = newline
1310
            self.BOM = True
1311
            return self._decode(infile, self.encoding)
1312
        #
1313
        # No encoding specified - so we need to check for UTF8/UTF16
1314
        for BOM, (encoding, final_encoding) in BOMS.items():
1315
            if not line.startswith(BOM):
1316
                continue
1317
            else:
1318
                # BOM discovered
1319
                self.encoding = final_encoding
1320
                if not final_encoding:
1321
                    self.BOM = True
1322
                    # UTF8
1323
                    # remove BOM
1324
                    newline = line[len(BOM):]
1325
                    if isinstance(infile, (list, tuple)):
1326
                        infile[0] = newline
1327
                    else:
1328
                        infile = newline
1329
                    # UTF8 - don't decode
1330
                    if isinstance(infile, StringTypes):
1331
                        return infile.splitlines(True)
1332
                    else:
1333
                        return infile
1334
                # UTF16 - have to decode
1335
                return self._decode(infile, encoding)
1336
        #
1337
        # No BOM discovered and no encoding specified, just return
1338
        if isinstance(infile, StringTypes):
1339
            # infile read from a file will be a single string
1340
            return infile.splitlines(True)
1341
        else:
1342
            return infile
1343
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1344
    def _a_to_u(self, aString):
1345
        """Decode ASCII strings to unicode if a self.encoding is specified."""
1346
        if self.encoding:
1347
            return aString.decode('ascii')
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1348
        else:
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1349
            return aString
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1350
1351
    def _decode(self, infile, encoding):
1352
        """
1353
        Decode infile to unicode. Using the specified encoding.
1354
        
1355
        if is a string, it also needs converting to a list.
1356
        """
1357
        if isinstance(infile, StringTypes):
1358
            # can't be unicode
1359
            # NOTE: Could raise a ``UnicodeDecodeError``
1360
            return infile.decode(encoding).splitlines(True)
1361
        for i, line in enumerate(infile):
1362
            if not isinstance(line, unicode):
1363
                # NOTE: The isinstance test here handles mixed lists of unicode/string
1364
                # NOTE: But the decode will break on any non-string values
1365
                # NOTE: Or could raise a ``UnicodeDecodeError``
1366
                infile[i] = line.decode(encoding)
1367
        return infile
1368
1369
    def _decode_element(self, line):
1370
        """Decode element to unicode if necessary."""
1371
        if not self.encoding:
1372
            return line
1373
        if isinstance(line, str) and self.default_encoding:
1374
            return line.decode(self.default_encoding)
1375
        return line
1376
1377
    def _str(self, value):
1378
        """
1379
        Used by ``stringify`` within validate, to turn non-string values
1380
        into strings.
1381
        """
1382
        if not isinstance(value, StringTypes):
1383
            return str(value)
1384
        else:
1385
            return value
1386
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1387
    def _parse(self, infile):
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1388
        """Actually parse the config file."""
1389
        temp_list_values = self.list_values
1390
        if self.unrepr:
1391
            self.list_values = False
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1392
        comment_list = []
1393
        done_start = False
1394
        this_section = self
1395
        maxline = len(infile) - 1
1396
        cur_index = -1
1397
        reset_comment = False
1398
        while cur_index < maxline:
1399
            if reset_comment:
1400
                comment_list = []
1401
            cur_index += 1
1402
            line = infile[cur_index]
1403
            sline = line.strip()
1404
            # do we have anything on the line ?
1405
            if not sline or sline.startswith('#'):
1406
                reset_comment = False
1407
                comment_list.append(line)
1408
                continue
1409
            if not done_start:
1410
                # preserve initial comment
1411
                self.initial_comment = comment_list
1412
                comment_list = []
1413
                done_start = True
1414
            reset_comment = True
1415
            # first we check if it's a section marker
1416
            mat = self._sectionmarker.match(line)
1417
            if mat is not None:
1418
                # is a section line
1419
                (indent, sect_open, sect_name, sect_close, comment) = (
1420
                    mat.groups())
1421
                if indent and (self.indent_type is None):
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1422
                    self.indent_type = indent
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1423
                cur_depth = sect_open.count('[')
1424
                if cur_depth != sect_close.count(']'):
1425
                    self._handle_error(
1426
                        "Cannot compute the section depth at line %s.",
1427
                        NestingError, infile, cur_index)
1428
                    continue
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1429
                #
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1430
                if cur_depth < this_section.depth:
1431
                    # the new section is dropping back to a previous level
1432
                    try:
1433
                        parent = self._match_depth(
1434
                            this_section,
1435
                            cur_depth).parent
1436
                    except SyntaxError:
1437
                        self._handle_error(
1438
                            "Cannot compute nesting level at line %s.",
1439
                            NestingError, infile, cur_index)
1440
                        continue
1441
                elif cur_depth == this_section.depth:
1442
                    # the new section is a sibling of the current section
1443
                    parent = this_section.parent
1444
                elif cur_depth == this_section.depth + 1:
1445
                    # the new section is a child the current section
1446
                    parent = this_section
1447
                else:
1448
                    self._handle_error(
1449
                        "Section too nested at line %s.",
1450
                        NestingError, infile, cur_index)
1451
                #
1452
                sect_name = self._unquote(sect_name)
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1453
                if parent.has_key(sect_name):
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1454
                    self._handle_error(
1455
                        'Duplicate section name at line %s.',
1456
                        DuplicateError, infile, cur_index)
1457
                    continue
1458
                # create the new section
1459
                this_section = Section(
1460
                    parent,
1461
                    cur_depth,
1462
                    self,
1463
                    name=sect_name)
1464
                parent[sect_name] = this_section
1465
                parent.inline_comments[sect_name] = comment
1466
                parent.comments[sect_name] = comment_list
1467
                continue
1468
            #
1469
            # it's not a section marker,
1470
            # so it should be a valid ``key = value`` line
1471
            mat = self._keyword.match(line)
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1472
            if mat is None:
1473
                # it neither matched as a keyword
1474
                # or a section marker
1475
                self._handle_error(
1476
                    'Invalid line at line "%s".',
1477
                    ParseError, infile, cur_index)
1478
            else:
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1479
                # is a keyword value
1480
                # value will include any inline comment
1481
                (indent, key, value) = mat.groups()
1482
                if indent and (self.indent_type is None):
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1483
                    self.indent_type = indent
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1484
                # check for a multiline value
1485
                if value[:3] in ['"""', "'''"]:
1486
                    try:
1487
                        (value, comment, cur_index) = self._multiline(
1488
                            value, infile, cur_index, maxline)
1489
                    except SyntaxError:
1490
                        self._handle_error(
1491
                            'Parse error in value at line %s.',
1492
                            ParseError, infile, cur_index)
1493
                        continue
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1494
                    else:
1495
                        if self.unrepr:
1496
                            comment = ''
1497
                            try:
1498
                                value = unrepr(value)
1499
                            except Exception, e:
1500
                                if type(e) == UnknownType:
1501
                                    msg = 'Unknown name or type in value at line %s.'
1502
                                else:
1503
                                    msg = 'Parse error in value at line %s.'
1504
                                self._handle_error(msg, UnreprError, infile,
1505
                                    cur_index)
1506
                                continue
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1507
                else:
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1508
                    if self.unrepr:
1509
                        comment = ''
1510
                        try:
1511
                            value = unrepr(value)
1512
                        except Exception, e:
1513
                            if isinstance(e, UnknownType):
1514
                                msg = 'Unknown name or type in value at line %s.'
1515
                            else:
1516
                                msg = 'Parse error in value at line %s.'
1517
                            self._handle_error(msg, UnreprError, infile,
1518
                                cur_index)
1519
                            continue
1520
                    else:
1521
                        # extract comment and lists
1522
                        try:
1523
                            (value, comment) = self._handle_value(value)
1524
                        except SyntaxError:
1525
                            self._handle_error(
1526
                                'Parse error in value at line %s.',
1527
                                ParseError, infile, cur_index)
1528
                            continue
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1529
                #
1530
                key = self._unquote(key)
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1531
                if this_section.has_key(key):
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1532
                    self._handle_error(
1533
                        'Duplicate keyword name at line %s.',
1534
                        DuplicateError, infile, cur_index)
1535
                    continue
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1536
                # add the key.
1537
                # we set unrepr because if we have got this far we will never
1538
                # be creating a new section
1539
                this_section.__setitem__(key, value, unrepr=True)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1540
                this_section.inline_comments[key] = comment
1541
                this_section.comments[key] = comment_list
1542
                continue
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1543
        #
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1544
        if self.indent_type is None:
1545
            # no indentation used, set the type accordingly
1546
            self.indent_type = ''
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1547
        #
1548
        if self._terminated:
1549
            comment_list.append('')
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1550
        # preserve the final comment
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1551
        if not self and not self.initial_comment:
1552
            self.initial_comment = comment_list
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1553
        elif not reset_comment:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1554
            self.final_comment = comment_list
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1555
        self.list_values = temp_list_values
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1556
1557
    def _match_depth(self, sect, depth):
1558
        """
1559
        Given a section and a depth level, walk back through the sections
1560
        parents to see if the depth level matches a previous section.
1561
        
1562
        Return a reference to the right section,
1563
        or raise a SyntaxError.
1564
        """
1565
        while depth < sect.depth:
1566
            if sect is sect.parent:
1567
                # we've reached the top level already
1568
                raise SyntaxError
1569
            sect = sect.parent
1570
        if sect.depth == depth:
1571
            return sect
1572
        # shouldn't get here
1573
        raise SyntaxError
1574
1575
    def _handle_error(self, text, ErrorClass, infile, cur_index):
1576
        """
1577
        Handle an error according to the error settings.
1578
        
1579
        Either raise the error or store it.
1580
        The error will have occured at ``cur_index``
1581
        """
1582
        line = infile[cur_index]
2900.1.2 by Vincent Ladeuil
Fix 149019 by using a proper line number when reporting errors.
1583
        cur_index += 1
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1584
        message = text % cur_index
1585
        error = ErrorClass(message, cur_index, line)
1586
        if self.raise_errors:
1587
            # raise the error - parsing stops here
1588
            raise error
1589
        # store the error
1590
        # reraise when parsing has finished
1591
        self._errors.append(error)
1592
1593
    def _unquote(self, value):
1594
        """Return an unquoted version of a value"""
1595
        if (value[0] == value[-1]) and (value[0] in ('"', "'")):
1596
            value = value[1:-1]
1597
        return value
1598
1599
    def _quote(self, value, multiline=True):
1600
        """
1601
        Return a safely quoted version of a value.
1602
        
1603
        Raise a ConfigObjError if the value cannot be safely quoted.
1604
        If multiline is ``True`` (default) then use triple quotes
1605
        if necessary.
1606
        
1607
        Don't quote values that don't need it.
1608
        Recursively quote members of a list and return a comma joined list.
1609
        Multiline is ``False`` for lists.
1610
        Obey list syntax for empty and single member lists.
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1611
        
1612
        If ``list_values=False`` then the value is only quoted if it contains
1613
        a ``\n`` (is multiline).
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1614
        
1615
        If ``write_empty_values`` is set, and the value is an empty string, it
1616
        won't be quoted.
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1617
        """
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1618
        if multiline and self.write_empty_values and value == '':
1619
            # Only if multiline is set, so that it is used for values not
1620
            # keys, and not values that are part of a list
1621
            return ''
1622
        if multiline and isinstance(value, (list, tuple)):
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1623
            if not value:
1624
                return ','
1625
            elif len(value) == 1:
1626
                return self._quote(value[0], multiline=False) + ','
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1627
            return ', '.join([self._quote(val, multiline=False)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1628
                for val in value])
1629
        if not isinstance(value, StringTypes):
1630
            if self.stringify:
1631
                value = str(value)
1632
            else:
1633
                raise TypeError, 'Value "%s" is not a string.' % value
1634
        squot = "'%s'"
1635
        dquot = '"%s"'
1636
        noquot = "%s"
1637
        wspace_plus = ' \r\t\n\v\t\'"'
1638
        tsquot = '"""%s"""'
1639
        tdquot = "'''%s'''"
1640
        if not value:
1641
            return '""'
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1642
        if (not self.list_values and '\n' not in value) or not (multiline and
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1643
                ((("'" in value) and ('"' in value)) or ('\n' in value))):
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1644
            if not self.list_values:
1645
                # we don't quote if ``list_values=False``
1646
                quot = noquot
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1647
            # for normal values either single or double quotes will do
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1648
            elif '\n' in value:
1649
                # will only happen if multiline is off - e.g. '\n' in key
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1650
                raise ConfigObjError, ('Value "%s" cannot be safely quoted.' %
1651
                    value)
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1652
            elif ((value[0] not in wspace_plus) and
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1653
                    (value[-1] not in wspace_plus) and
1654
                    (',' not in value)):
1655
                quot = noquot
1656
            else:
1657
                if ("'" in value) and ('"' in value):
1658
                    raise ConfigObjError, (
1659
                        'Value "%s" cannot be safely quoted.' % value)
1660
                elif '"' in value:
1661
                    quot = squot
1662
                else:
1663
                    quot = dquot
1664
        else:
1665
            # if value has '\n' or "'" *and* '"', it will need triple quotes
1666
            if (value.find('"""') != -1) and (value.find("'''") != -1):
1667
                raise ConfigObjError, (
1668
                    'Value "%s" cannot be safely quoted.' % value)
1669
            if value.find('"""') == -1:
1670
                quot = tdquot
1671
            else:
1672
                quot = tsquot
1673
        return quot % value
1674
1675
    def _handle_value(self, value):
1676
        """
1677
        Given a value string, unquote, remove comment,
1678
        handle lists. (including empty and single member lists)
1679
        """
1680
        # do we look for lists in values ?
1681
        if not self.list_values:
1682
            mat = self._nolistvalue.match(value)
1683
            if mat is None:
1684
                raise SyntaxError
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1685
            # NOTE: we don't unquote here
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1686
            return mat.groups()
1687
        #
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1688
        mat = self._valueexp.match(value)
1689
        if mat is None:
1690
            # the value is badly constructed, probably badly quoted,
1691
            # or an invalid list
1692
            raise SyntaxError
1693
        (list_values, single, empty_list, comment) = mat.groups()
1694
        if (list_values == '') and (single is None):
1695
            # change this if you want to accept empty values
1696
            raise SyntaxError
1697
        # NOTE: note there is no error handling from here if the regex
1698
        # is wrong: then incorrect values will slip through
1699
        if empty_list is not None:
1700
            # the single comma - meaning an empty list
1701
            return ([], comment)
1702
        if single is not None:
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1703
            # handle empty values
1704
            if list_values and not single:
1705
                # FIXME: the '' is a workaround because our regex now matches
1706
                #   '' at the end of a list if it has a trailing comma
1707
                single = None
1708
            else:
1709
                single = single or '""'
1710
                single = self._unquote(single)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1711
        if list_values == '':
1712
            # not a list value
1713
            return (single, comment)
1714
        the_list = self._listvalueexp.findall(list_values)
1715
        the_list = [self._unquote(val) for val in the_list]
1716
        if single is not None:
1717
            the_list += [single]
1718
        return (the_list, comment)
1719
1720
    def _multiline(self, value, infile, cur_index, maxline):
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1721
        """Extract the value, where we are in a multiline situation."""
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1722
        quot = value[:3]
1723
        newvalue = value[3:]
1724
        single_line = self._triple_quote[quot][0]
1725
        multi_line = self._triple_quote[quot][1]
1726
        mat = single_line.match(value)
1727
        if mat is not None:
1728
            retval = list(mat.groups())
1729
            retval.append(cur_index)
1730
            return retval
1731
        elif newvalue.find(quot) != -1:
1732
            # somehow the triple quote is missing
1733
            raise SyntaxError
1734
        #
1735
        while cur_index < maxline:
1736
            cur_index += 1
1737
            newvalue += '\n'
1738
            line = infile[cur_index]
1739
            if line.find(quot) == -1:
1740
                newvalue += line
1741
            else:
1742
                # end of multiline, process it
1743
                break
1744
        else:
1745
            # we've got to the end of the config, oops...
1746
            raise SyntaxError
1747
        mat = multi_line.match(line)
1748
        if mat is None:
1749
            # a badly formed line
1750
            raise SyntaxError
1751
        (value, comment) = mat.groups()
1752
        return (newvalue + value, comment, cur_index)
1753
1754
    def _handle_configspec(self, configspec):
1755
        """Parse the configspec."""
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1756
        # FIXME: Should we check that the configspec was created with the 
1757
        #   correct settings ? (i.e. ``list_values=False``)
1758
        if not isinstance(configspec, ConfigObj):
1759
            try:
1760
                configspec = ConfigObj(
1761
                    configspec,
1762
                    raise_errors=True,
1763
                    file_error=True,
1764
                    list_values=False)
1765
            except ConfigObjError, e:
1766
                # FIXME: Should these errors have a reference
1767
                # to the already parsed ConfigObj ?
1768
                raise ConfigspecError('Parsing configspec failed: %s' % e)
1769
            except IOError, e:
1770
                raise IOError('Reading configspec failed: %s' % e)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1771
        self._set_configspec_value(configspec, self)
1772
1773
    def _set_configspec_value(self, configspec, section):
1774
        """Used to recursively set configspec values."""
1775
        if '__many__' in configspec.sections:
1776
            section.configspec['__many__'] = configspec['__many__']
1777
            if len(configspec.sections) > 1:
1778
                # FIXME: can we supply any useful information here ?
1779
                raise RepeatSectionError
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1780
        if hasattr(configspec, 'initial_comment'):
1781
            section._configspec_initial_comment = configspec.initial_comment
1782
            section._configspec_final_comment = configspec.final_comment
1783
            section._configspec_encoding = configspec.encoding
1784
            section._configspec_BOM = configspec.BOM
1785
            section._configspec_newlines = configspec.newlines
1786
            section._configspec_indent_type = configspec.indent_type
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1787
        for entry in configspec.scalars:
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1788
            section._configspec_comments[entry] = configspec.comments[entry]
1789
            section._configspec_inline_comments[entry] = (
1790
                configspec.inline_comments[entry])
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1791
            section.configspec[entry] = configspec[entry]
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1792
            section._order.append(entry)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1793
        for entry in configspec.sections:
1794
            if entry == '__many__':
1795
                continue
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1796
            section._cs_section_comments[entry] = configspec.comments[entry]
1797
            section._cs_section_inline_comments[entry] = (
1798
                configspec.inline_comments[entry])
1799
            if not section.has_key(entry):
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1800
                section[entry] = {}
1801
            self._set_configspec_value(configspec[entry], section[entry])
1802
1803
    def _handle_repeat(self, section, configspec):
1804
        """Dynamically assign configspec for repeated section."""
1805
        try:
1806
            section_keys = configspec.sections
1807
            scalar_keys = configspec.scalars
1808
        except AttributeError:
1809
            section_keys = [entry for entry in configspec 
1810
                                if isinstance(configspec[entry], dict)]
1811
            scalar_keys = [entry for entry in configspec 
1812
                                if not isinstance(configspec[entry], dict)]
1813
        if '__many__' in section_keys and len(section_keys) > 1:
1814
            # FIXME: can we supply any useful information here ?
1815
            raise RepeatSectionError
1816
        scalars = {}
1817
        sections = {}
1818
        for entry in scalar_keys:
1819
            val = configspec[entry]
1820
            scalars[entry] = val
1821
        for entry in section_keys:
1822
            val = configspec[entry]
1823
            if entry == '__many__':
1824
                scalars[entry] = val
1825
                continue
1826
            sections[entry] = val
1827
        #
1828
        section.configspec = scalars
1829
        for entry in sections:
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1830
            if not section.has_key(entry):
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1831
                section[entry] = {}
1832
            self._handle_repeat(section[entry], sections[entry])
1833
1834
    def _write_line(self, indent_string, entry, this_entry, comment):
1835
        """Write an individual line, for the write method"""
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1836
        # NOTE: the calls to self._quote here handles non-StringType values.
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1837
        if not self.unrepr:
1838
            val = self._decode_element(self._quote(this_entry))
1839
        else:
1840
            val = repr(this_entry)
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1841
        return '%s%s%s%s%s' % (
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1842
            indent_string,
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1843
            self._decode_element(self._quote(entry, multiline=False)),
1844
            self._a_to_u(' = '),
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1845
            val,
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1846
            self._decode_element(comment))
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1847
1848
    def _write_marker(self, indent_string, depth, entry, comment):
1849
        """Write a section marker line"""
1850
        return '%s%s%s%s%s' % (
1851
            indent_string,
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1852
            self._a_to_u('[' * depth),
1853
            self._quote(self._decode_element(entry), multiline=False),
1854
            self._a_to_u(']' * depth),
1855
            self._decode_element(comment))
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1856
1857
    def _handle_comment(self, comment):
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1858
        """Deal with a comment."""
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1859
        if not comment:
1860
            return ''
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1861
        start = self.indent_type
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1862
        if not comment.startswith('#'):
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1863
            start += self._a_to_u(' # ')
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1864
        return (start + comment)
1865
1866
    # Public methods
1867
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1868
    def write(self, outfile=None, section=None):
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1869
        """
1870
        Write the current ConfigObj as a file
1871
        
1872
        tekNico: FIXME: use StringIO instead of real files
1873
        
1874
        >>> filename = a.filename
1875
        >>> a.filename = 'test.ini'
1876
        >>> a.write()
1877
        >>> a.filename = filename
1878
        >>> a == ConfigObj('test.ini', raise_errors=True)
1879
        1
1880
        """
1881
        if self.indent_type is None:
1882
            # this can be true if initialised from a dictionary
1883
            self.indent_type = DEFAULT_INDENT_TYPE
1884
        #
1885
        out = []
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1886
        cs = self._a_to_u('#')
1887
        csp = self._a_to_u('# ')
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1888
        if section is None:
1889
            int_val = self.interpolation
1890
            self.interpolation = False
1891
            section = self
1892
            for line in self.initial_comment:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1893
                line = self._decode_element(line)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1894
                stripped_line = line.strip()
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1895
                if stripped_line and not stripped_line.startswith(cs):
1896
                    line = csp + line
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1897
                out.append(line)
1898
        #
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1899
        indent_string = self.indent_type * section.depth
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1900
        for entry in (section.scalars + section.sections):
1901
            if entry in section.defaults:
1902
                # don't write out default values
1903
                continue
1904
            for comment_line in section.comments[entry]:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1905
                comment_line = self._decode_element(comment_line.lstrip())
1906
                if comment_line and not comment_line.startswith(cs):
1907
                    comment_line = csp + comment_line
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1908
                out.append(indent_string + comment_line)
1909
            this_entry = section[entry]
1910
            comment = self._handle_comment(section.inline_comments[entry])
1911
            #
1912
            if isinstance(this_entry, dict):
1913
                # a section
1914
                out.append(self._write_marker(
1915
                    indent_string,
1916
                    this_entry.depth,
1917
                    entry,
1918
                    comment))
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1919
                out.extend(self.write(section=this_entry))
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1920
            else:
1921
                out.append(self._write_line(
1922
                    indent_string,
1923
                    entry,
1924
                    this_entry,
1925
                    comment))
1926
        #
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1927
        if section is self:
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1928
            for line in self.final_comment:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1929
                line = self._decode_element(line)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1930
                stripped_line = line.strip()
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1931
                if stripped_line and not stripped_line.startswith(cs):
1932
                    line = csp + line
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1933
                out.append(line)
1934
            self.interpolation = int_val
1935
        #
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1936
        if section is not self:
1937
            return out
1938
        #
1939
        if (self.filename is None) and (outfile is None):
1940
            # output a list of lines
1941
            # might need to encode
1942
            # NOTE: This will *screw* UTF16, each line will start with the BOM
1943
            if self.encoding:
1944
                out = [l.encode(self.encoding) for l in out]
1945
            if (self.BOM and ((self.encoding is None) or
1946
                (BOM_LIST.get(self.encoding.lower()) == 'utf_8'))):
1947
                # Add the UTF8 BOM
1948
                if not out:
1949
                    out.append('')
1950
                out[0] = BOM_UTF8 + out[0]
1951
            return out
1952
        #
1953
        # Turn the list to a string, joined with correct newlines
1954
        output = (self._a_to_u(self.newlines or os.linesep)
1955
            ).join(out)
1956
        if self.encoding:
1957
            output = output.encode(self.encoding)
1958
        if (self.BOM and ((self.encoding is None) or
1959
            (BOM_LIST.get(self.encoding.lower()) == 'utf_8'))):
1960
            # Add the UTF8 BOM
1961
            output = BOM_UTF8 + output
1962
        if outfile is not None:
1963
            outfile.write(output)
1964
        else:
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1965
            h = open(self.filename, 'wb')
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1966
            h.write(output)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1967
            h.close()
1968
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
1969
    def validate(self, validator, preserve_errors=False, copy=False,
1970
        section=None):
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1971
        """
1972
        Test the ConfigObj against a configspec.
1973
        
1974
        It uses the ``validator`` object from *validate.py*.
1975
        
1976
        To run ``validate`` on the current ConfigObj, call: ::
1977
        
1978
            test = config.validate(validator)
1979
        
1980
        (Normally having previously passed in the configspec when the ConfigObj
1981
        was created - you can dynamically assign a dictionary of checks to the
1982
        ``configspec`` attribute of a section though).
1983
        
1984
        It returns ``True`` if everything passes, or a dictionary of
1985
        pass/fails (True/False). If every member of a subsection passes, it
1986
        will just have the value ``True``. (It also returns ``False`` if all
1987
        members fail).
1988
        
1989
        In addition, it converts the values from strings to their native
1990
        types if their checks pass (and ``stringify`` is set).
1991
        
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1992
        If ``preserve_errors`` is ``True`` (``False`` is default) then instead
1993
        of a marking a fail with a ``False``, it will preserve the actual
1994
        exception object. This can contain info about the reason for failure.
1995
        For example the ``VdtValueTooSmallError`` indeicates that the value
1996
        supplied was too small. If a value (or section) is missing it will
1997
        still be marked as ``False``.
1998
        
1999
        You must have the validate module to use ``preserve_errors=True``.
2000
        
2001
        You can then use the ``flatten_errors`` function to turn your nested
2002
        results dictionary into a flattened list of failures - useful for
2003
        displaying meaningful error messages.
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2004
        """
2005
        if section is None:
2006
            if self.configspec is None:
2007
                raise ValueError, 'No configspec supplied.'
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2008
            if preserve_errors:
3224.5.1 by Andrew Bennetts
Lots of assorted hackery to reduce the number of imports for common operations. Improves 'rocks', 'st' and 'help' times by ~50ms on my laptop.
2009
                try:
2010
                    from validate import VdtMissingValue
2011
                except ImportError:
2012
                    VdtMissingValue = None
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2013
                if VdtMissingValue is None:
2014
                    raise ImportError('Missing validate module.')
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2015
            section = self
2016
        #
2017
        spec_section = section.configspec
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
2018
        if copy and hasattr(section, '_configspec_initial_comment'):
2019
            section.initial_comment = section._configspec_initial_comment
2020
            section.final_comment = section._configspec_final_comment
2021
            section.encoding = section._configspec_encoding
2022
            section.BOM = section._configspec_BOM
2023
            section.newlines = section._configspec_newlines
2024
            section.indent_type = section._configspec_indent_type
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2025
        if '__many__' in section.configspec:
2026
            many = spec_section['__many__']
2027
            # dynamically assign the configspecs
2028
            # for the sections below
2029
            for entry in section.sections:
2030
                self._handle_repeat(section[entry], many)
2031
        #
2032
        out = {}
2033
        ret_true = True
2034
        ret_false = True
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
2035
        order = [k for k in section._order if k in spec_section]
2036
        order += [k for k in spec_section if k not in order]
2037
        for entry in order:
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2038
            if entry == '__many__':
2039
                continue
2040
            if (not entry in section.scalars) or (entry in section.defaults):
2041
                # missing entries
2042
                # or entries from defaults
2043
                missing = True
2044
                val = None
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
2045
                if copy and not entry in section.scalars:
2046
                    # copy comments
2047
                    section.comments[entry] = (
2048
                        section._configspec_comments.get(entry, []))
2049
                    section.inline_comments[entry] = (
2050
                        section._configspec_inline_comments.get(entry, ''))
2051
                #
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2052
            else:
2053
                missing = False
2054
                val = section[entry]
2055
            try:
2056
                check = validator.check(spec_section[entry],
2057
                                        val,
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2058
                                        missing=missing
2059
                                        )
2060
            except validator.baseErrorClass, e:
2061
                if not preserve_errors or isinstance(e, VdtMissingValue):
2062
                    out[entry] = False
2063
                else:
2064
                    # preserve the error
2065
                    out[entry] = e
2066
                    ret_false = False
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2067
                ret_true = False
2068
            else:
2069
                ret_false = False
2070
                out[entry] = True
2071
                if self.stringify or missing:
2072
                    # if we are doing type conversion
2073
                    # or the value is a supplied default
2074
                    if not self.stringify:
2075
                        if isinstance(check, (list, tuple)):
2076
                            # preserve lists
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2077
                            check = [self._str(item) for item in check]
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2078
                        elif missing and check is None:
2079
                            # convert the None from a default to a ''
2080
                            check = ''
2081
                        else:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2082
                            check = self._str(check)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2083
                    if (check != val) or missing:
2084
                        section[entry] = check
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
2085
                if not copy and missing and entry not in section.defaults:
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2086
                    section.defaults.append(entry)
2087
        #
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
2088
        # Missing sections will have been created as empty ones when the
2089
        # configspec was read.
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2090
        for entry in section.sections:
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
2091
            # FIXME: this means DEFAULT is not copied in copy mode
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2092
            if section is self and entry == 'DEFAULT':
2093
                continue
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
2094
            if copy:
2095
                section.comments[entry] = section._cs_section_comments[entry]
2096
                section.inline_comments[entry] = (
2097
                    section._cs_section_inline_comments[entry])
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2098
            check = self.validate(validator, preserve_errors=preserve_errors,
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
2099
                copy=copy, section=section[entry])
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2100
            out[entry] = check
2101
            if check == False:
2102
                ret_true = False
2103
            elif check == True:
2104
                ret_false = False
2105
            else:
2106
                ret_true = False
2107
                ret_false = False
2108
        #
2109
        if ret_true:
2110
            return True
2111
        elif ret_false:
2112
            return False
2113
        else:
2114
            return out
2115
2116
class SimpleVal(object):
2117
    """
2118
    A simple validator.
2119
    Can be used to check that all members expected are present.
2120
    
2121
    To use it, provide a configspec with all your members in (the value given
2122
    will be ignored). Pass an instance of ``SimpleVal`` to the ``validate``
2123
    method of your ``ConfigObj``. ``validate`` will return ``True`` if all
2124
    members are present, or a dictionary with True/False meaning
2125
    present/missing. (Whole missing sections will be replaced with ``False``)
2126
    """
2127
    
2128
    def __init__(self):
2129
        self.baseErrorClass = ConfigObjError
2130
    
2131
    def check(self, check, member, missing=False):
2132
        """A dummy check method, always returns the value unchanged."""
2133
        if missing:
2134
            raise self.baseErrorClass
2135
        return member
2136
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2137
# Check / processing functions for options
2138
def flatten_errors(cfg, res, levels=None, results=None):
2139
    """
2140
    An example function that will turn a nested dictionary of results
2141
    (as returned by ``ConfigObj.validate``) into a flat list.
2142
    
2143
    ``cfg`` is the ConfigObj instance being checked, ``res`` is the results
2144
    dictionary returned by ``validate``.
2145
    
2146
    (This is a recursive function, so you shouldn't use the ``levels`` or
2147
    ``results`` arguments - they are used by the function.
2148
    
2149
    Returns a list of keys that failed. Each member of the list is a tuple :
2150
    ::
2151
    
2152
        ([list of sections...], key, result)
2153
    
2154
    If ``validate`` was called with ``preserve_errors=False`` (the default)
2155
    then ``result`` will always be ``False``.
2156
2157
    *list of sections* is a flattened list of sections that the key was found
2158
    in.
2159
    
2160
    If the section was missing then key will be ``None``.
2161
    
2162
    If the value (or section) was missing then ``result`` will be ``False``.
2163
    
2164
    If ``validate`` was called with ``preserve_errors=True`` and a value
2165
    was present, but failed the check, then ``result`` will be the exception
2166
    object returned. You can use this as a string that describes the failure.
2167
    
2168
    For example *The value "3" is of the wrong type*.
2169
    
2170
    >>> import validate
2171
    >>> vtor = validate.Validator()
2172
    >>> my_ini = '''
2173
    ...     option1 = True
2174
    ...     [section1]
2175
    ...     option1 = True
2176
    ...     [section2]
2177
    ...     another_option = Probably
2178
    ...     [section3]
2179
    ...     another_option = True
2180
    ...     [[section3b]]
2181
    ...     value = 3
2182
    ...     value2 = a
2183
    ...     value3 = 11
2184
    ...     '''
2185
    >>> my_cfg = '''
2186
    ...     option1 = boolean()
2187
    ...     option2 = boolean()
2188
    ...     option3 = boolean(default=Bad_value)
2189
    ...     [section1]
2190
    ...     option1 = boolean()
2191
    ...     option2 = boolean()
2192
    ...     option3 = boolean(default=Bad_value)
2193
    ...     [section2]
2194
    ...     another_option = boolean()
2195
    ...     [section3]
2196
    ...     another_option = boolean()
2197
    ...     [[section3b]]
2198
    ...     value = integer
2199
    ...     value2 = integer
2200
    ...     value3 = integer(0, 10)
2201
    ...         [[[section3b-sub]]]
2202
    ...         value = string
2203
    ...     [section4]
2204
    ...     another_option = boolean()
2205
    ...     '''
2206
    >>> cs = my_cfg.split('\\n')
2207
    >>> ini = my_ini.split('\\n')
2208
    >>> cfg = ConfigObj(ini, configspec=cs)
2209
    >>> res = cfg.validate(vtor, preserve_errors=True)
2210
    >>> errors = []
2211
    >>> for entry in flatten_errors(cfg, res):
2212
    ...     section_list, key, error = entry
2213
    ...     section_list.insert(0, '[root]')
2214
    ...     if key is not None:
2215
    ...        section_list.append(key)
2216
    ...     else:
2217
    ...         section_list.append('[missing]')
2218
    ...     section_string = ', '.join(section_list)
2219
    ...     errors.append((section_string, ' = ', error))
2220
    >>> errors.sort()
2221
    >>> for entry in errors:
2222
    ...     print entry[0], entry[1], (entry[2] or 0)
2223
    [root], option2  =  0
2224
    [root], option3  =  the value "Bad_value" is of the wrong type.
2225
    [root], section1, option2  =  0
2226
    [root], section1, option3  =  the value "Bad_value" is of the wrong type.
2227
    [root], section2, another_option  =  the value "Probably" is of the wrong type.
2228
    [root], section3, section3b, section3b-sub, [missing]  =  0
2229
    [root], section3, section3b, value2  =  the value "a" is of the wrong type.
2230
    [root], section3, section3b, value3  =  the value "11" is too big.
2231
    [root], section4, [missing]  =  0
2232
    """
2233
    if levels is None:
2234
        # first time called
2235
        levels = []
2236
        results = []
2237
    if res is True:
2238
        return results
2239
    if res is False:
2240
        results.append((levels[:], None, False))
2241
        if levels:
2242
            levels.pop()
2243
        return results
2244
    for (key, val) in res.items():
2245
        if val == True:
2246
            continue
2247
        if isinstance(cfg.get(key), dict):
2248
            # Go down one level
2249
            levels.append(key)
2250
            flatten_errors(cfg[key], val, levels, results)
2251
            continue
2252
        results.append((levels[:], key, val))
2253
    #
2254
    # Go up one level
2255
    if levels:
2256
        levels.pop()
2257
    #
2258
    return results
2259
2991.2.1 by Vincent Ladeuil
Update configobj to version 4.4.0:
2260
"""*A programming language is a medium of expression.* - Paul Graham"""