/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.
3
# Copyright (C) 2005 Michael Foord, Nicola Larosa
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
"""
22
    >>> z = ConfigObj()
23
    >>> z['a'] = 'a'
24
    >>> z['sect'] = {
25
    ...    'subsect': {
26
    ...         'a': 'fish',
27
    ...         'b': 'wobble',
28
    ...     },
29
    ...     'member': 'value',
30
    ... }
31
    >>> x = ConfigObj(z.write())
32
    >>> z == x
33
    1
34
"""
35
36
import sys
37
INTP_VER = sys.version_info[:2]
38
if INTP_VER < (2, 2):
39
    raise RuntimeError("Python v.2.2 or later needed")
40
41
import os, re
42
from types import StringTypes
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
43
from warnings import warn
44
from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE
45
46
# A dictionary mapping BOM to
47
# the encoding to decode with, and what to set the
48
# encoding attribute to.
49
BOMS = {
50
    BOM_UTF8: ('utf_8', None),
51
    BOM_UTF16_BE: ('utf16_be', 'utf_16'),
52
    BOM_UTF16_LE: ('utf16_le', 'utf_16'),
53
    BOM_UTF16: ('utf_16', 'utf_16'),
54
    }
55
# All legal variants of the BOM codecs.
56
# TODO: the list of aliases is not meant to be exhaustive, is there a
57
#   better way ?
58
BOM_LIST = {
59
    'utf_16': 'utf_16',
60
    'u16': 'utf_16',
61
    'utf16': 'utf_16',
62
    'utf-16': 'utf_16',
63
    'utf16_be': 'utf16_be',
64
    'utf_16_be': 'utf16_be',
65
    'utf-16be': 'utf16_be',
66
    'utf16_le': 'utf16_le',
67
    'utf_16_le': 'utf16_le',
68
    'utf-16le': 'utf16_le',
69
    'utf_8': 'utf_8',
70
    'u8': 'utf_8',
71
    'utf': 'utf_8',
72
    'utf8': 'utf_8',
73
    'utf-8': 'utf_8',
74
    }
75
76
# Map of encodings to the BOM to write.
77
BOM_SET = {
78
    'utf_8': BOM_UTF8,
79
    'utf_16': BOM_UTF16,
80
    'utf16_be': BOM_UTF16_BE,
81
    'utf16_le': BOM_UTF16_LE,
82
    None: BOM_UTF8
83
    }
84
85
try:
86
    from validate import VdtMissingValue
87
except ImportError:
88
    VdtMissingValue = None
89
90
try:
91
    enumerate
92
except NameError:
93
    def enumerate(obj):
94
        """enumerate for Python 2.2."""
95
        i = -1
96
        for item in obj:
97
            i += 1
98
            yield i, item
99
100
try:
101
    True, False
102
except NameError:
103
    True, False = 1, 0
104
105
106
__version__ = '4.2.0beta2'
107
108
__revision__ = '$Id: configobj.py 156 2006-01-31 14:57:08Z fuzzyman $'
1185.12.49 by Aaron Bentley
Switched to ConfigObj
109
110
__docformat__ = "restructuredtext en"
111
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
112
# NOTE: Does it make sense to have the following in __all__ ?
113
# NOTE: DEFAULT_INDENT_TYPE, NUM_INDENT_SPACES, MAX_INTERPOL_DEPTH
114
# NOTE: If used as from configobj import...
115
# NOTE: They are effectively read only
1185.12.49 by Aaron Bentley
Switched to ConfigObj
116
__all__ = (
117
    '__version__',
118
    'DEFAULT_INDENT_TYPE',
119
    'NUM_INDENT_SPACES',
120
    'MAX_INTERPOL_DEPTH',
121
    'ConfigObjError',
122
    'NestingError',
123
    'ParseError',
124
    'DuplicateError',
125
    'ConfigspecError',
126
    'ConfigObj',
127
    'SimpleVal',
128
    'InterpolationError',
129
    'InterpolationDepthError',
130
    'MissingInterpolationOption',
131
    'RepeatSectionError',
132
    '__docformat__',
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
133
    'flatten_errors',
1185.12.49 by Aaron Bentley
Switched to ConfigObj
134
)
135
136
DEFAULT_INDENT_TYPE = ' '
137
NUM_INDENT_SPACES = 4
138
MAX_INTERPOL_DEPTH = 10
139
140
OPTION_DEFAULTS = {
141
    'interpolation': True,
142
    'raise_errors': False,
143
    'list_values': True,
144
    'create_empty': False,
145
    'file_error': False,
146
    'configspec': None,
147
    'stringify': True,
148
    # option may be set to one of ('', ' ', '\t')
149
    'indent_type': None,
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
150
    'encoding': None,
151
    'default_encoding': None,
1185.12.49 by Aaron Bentley
Switched to ConfigObj
152
}
153
154
class ConfigObjError(SyntaxError):
155
    """
156
    This is the base class for all errors that ConfigObj raises.
157
    It is a subclass of SyntaxError.
158
    
159
    >>> raise ConfigObjError
160
    Traceback (most recent call last):
161
    ConfigObjError
162
    """
163
    def __init__(self, message='', line_number=None, line=''):
164
        self.line = line
165
        self.line_number = line_number
166
        self.message = message
167
        SyntaxError.__init__(self, message)
168
169
class NestingError(ConfigObjError):
170
    """
171
    This error indicates a level of nesting that doesn't match.
172
    
173
    >>> raise NestingError
174
    Traceback (most recent call last):
175
    NestingError
176
    """
177
178
class ParseError(ConfigObjError):
179
    """
180
    This error indicates that a line is badly written.
181
    It is neither a valid ``key = value`` line,
182
    nor a valid section marker line.
183
    
184
    >>> raise ParseError
185
    Traceback (most recent call last):
186
    ParseError
187
    """
188
189
class DuplicateError(ConfigObjError):
190
    """
191
    The keyword or section specified already exists.
192
    
193
    >>> raise DuplicateError
194
    Traceback (most recent call last):
195
    DuplicateError
196
    """
197
198
class ConfigspecError(ConfigObjError):
199
    """
200
    An error occured whilst parsing a configspec.
201
    
202
    >>> raise ConfigspecError
203
    Traceback (most recent call last):
204
    ConfigspecError
205
    """
206
207
class InterpolationError(ConfigObjError):
208
    """Base class for the two interpolation errors."""
209
210
class InterpolationDepthError(InterpolationError):
211
    """Maximum interpolation depth exceeded in string interpolation."""
212
213
    def __init__(self, option):
214
        """
215
        >>> raise InterpolationDepthError('yoda')
216
        Traceback (most recent call last):
217
        InterpolationDepthError: max interpolation depth exceeded in value "yoda".
218
        """
219
        InterpolationError.__init__(
220
            self,
221
            'max interpolation depth exceeded in value "%s".' % option)
222
223
class RepeatSectionError(ConfigObjError):
224
    """
225
    This error indicates additional sections in a section with a
226
    ``__many__`` (repeated) section.
227
    
228
    >>> raise RepeatSectionError
229
    Traceback (most recent call last):
230
    RepeatSectionError
231
    """
232
233
class MissingInterpolationOption(InterpolationError):
234
    """A value specified for interpolation was missing."""
235
236
    def __init__(self, option):
237
        """
238
        >>> raise MissingInterpolationOption('yoda')
239
        Traceback (most recent call last):
240
        MissingInterpolationOption: missing option "yoda" in interpolation.
241
        """
242
        InterpolationError.__init__(
243
            self,
244
            'missing option "%s" in interpolation.' % option)
245
246
class Section(dict):
247
    """
248
    A dictionary-like object that represents a section in a config file.
249
    
250
    It does string interpolation if the 'interpolate' attribute
251
    of the 'main' object is set to True.
252
    
253
    Interpolation is tried first from the 'DEFAULT' section of this object,
254
    next from the 'DEFAULT' section of the parent, lastly the main object.
255
    
256
    A Section will behave like an ordered dictionary - following the
257
    order of the ``scalars`` and ``sections`` attributes.
258
    You can use this to change the order of members.
259
    
260
    Iteration follows the order: scalars, then sections.
261
    """
262
263
    _KEYCRE = re.compile(r"%\(([^)]*)\)s|.")
264
265
    def __init__(self, parent, depth, main, indict=None, name=None):
266
        """
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
267
        * parent is the section above
268
        * depth is the depth level of this section
269
        * main is the main ConfigObj
270
        * indict is a dictionary to initialise the section with
1185.12.49 by Aaron Bentley
Switched to ConfigObj
271
        """
272
        if indict is None:
273
            indict = {}
274
        dict.__init__(self)
275
        # used for nesting level *and* interpolation
276
        self.parent = parent
277
        # used for the interpolation attribute
278
        self.main = main
279
        # level of nesting depth of this Section
280
        self.depth = depth
281
        # the sequence of scalar values in this Section
282
        self.scalars = []
283
        # the sequence of sections in this Section
284
        self.sections = []
285
        # purely for information
286
        self.name = name
287
        # for comments :-)
288
        self.comments = {}
289
        self.inline_comments = {}
290
        # for the configspec
291
        self.configspec = {}
292
        # for defaults
293
        self.defaults = []
294
        #
295
        # we do this explicitly so that __setitem__ is used properly
296
        # (rather than just passing to ``dict.__init__``)
297
        for entry in indict:
298
            self[entry] = indict[entry]
299
300
    def _interpolate(self, value):
301
        """Nicked from ConfigParser."""
302
        depth = MAX_INTERPOL_DEPTH
303
        # loop through this until it's done
304
        while depth:
305
            depth -= 1
306
            if value.find("%(") != -1:
307
                value = self._KEYCRE.sub(self._interpolation_replace, value)
308
            else:
309
                break
310
        else:
311
            raise InterpolationDepthError(value)
312
        return value
313
314
    def _interpolation_replace(self, match):
315
        """ """
316
        s = match.group(1)
317
        if s is None:
318
            return match.group()
319
        else:
320
            # switch off interpolation before we try and fetch anything !
321
            self.main.interpolation = False
322
            # try the 'DEFAULT' member of *this section* first
323
            val = self.get('DEFAULT', {}).get(s)
324
            # try the 'DEFAULT' member of the *parent section* next
325
            if val is None:
326
                val = self.parent.get('DEFAULT', {}).get(s)
327
            # last, try the 'DEFAULT' member of the *main section*
328
            if val is None:
329
                val = self.main.get('DEFAULT', {}).get(s)
330
            self.main.interpolation = True
331
            if val is None:
332
                raise MissingInterpolationOption(s)
333
            return val
334
335
    def __getitem__(self, key):
336
        """Fetch the item and do string interpolation."""
337
        val = dict.__getitem__(self, key)
338
        if self.main.interpolation and isinstance(val, StringTypes):
339
            return self._interpolate(val)
340
        return val
341
342
    def __setitem__(self, key, value):
343
        """
344
        Correctly set a value.
345
        
346
        Making dictionary values Section instances.
347
        (We have to special case 'Section' instances - which are also dicts)
348
        
349
        Keys must be strings.
350
        Values need only be strings (or lists of strings) if
351
        ``main.stringify`` is set.
352
        """
353
        if not isinstance(key, StringTypes):
354
            raise ValueError, 'The key "%s" is not a string.' % key
355
        # add the comment
1963.2.1 by Robey Pointer
remove usage of has_key()
356
        if key not in self.comments:
1185.12.49 by Aaron Bentley
Switched to ConfigObj
357
            self.comments[key] = []
358
            self.inline_comments[key] = ''
359
        # remove the entry from defaults
360
        if key in self.defaults:
361
            self.defaults.remove(key)
362
        #
363
        if isinstance(value, Section):
1963.2.1 by Robey Pointer
remove usage of has_key()
364
            if key not in self:
1185.12.49 by Aaron Bentley
Switched to ConfigObj
365
                self.sections.append(key)
366
            dict.__setitem__(self, key, value)
367
        elif isinstance(value, dict):
368
            # First create the new depth level,
369
            # then create the section
1963.2.1 by Robey Pointer
remove usage of has_key()
370
            if key not in self:
1185.12.49 by Aaron Bentley
Switched to ConfigObj
371
                self.sections.append(key)
372
            new_depth = self.depth + 1
373
            dict.__setitem__(
374
                self,
375
                key,
376
                Section(
377
                    self,
378
                    new_depth,
379
                    self.main,
380
                    indict=value,
381
                    name=key))
382
        else:
1963.2.1 by Robey Pointer
remove usage of has_key()
383
            if key not in self:
1185.12.49 by Aaron Bentley
Switched to ConfigObj
384
                self.scalars.append(key)
385
            if not self.main.stringify:
386
                if isinstance(value, StringTypes):
387
                    pass
388
                elif isinstance(value, (list, tuple)):
389
                    for entry in value:
390
                        if not isinstance(entry, StringTypes):
391
                            raise TypeError, (
392
                                'Value is not a string "%s".' % entry)
393
                else:
394
                    raise TypeError, 'Value is not a string "%s".' % value
395
            dict.__setitem__(self, key, value)
396
397
    def __delitem__(self, key):
398
        """Remove items from the sequence when deleting."""
399
        dict. __delitem__(self, key)
400
        if key in self.scalars:
401
            self.scalars.remove(key)
402
        else:
403
            self.sections.remove(key)
404
        del self.comments[key]
405
        del self.inline_comments[key]
406
407
    def get(self, key, default=None):
408
        """A version of ``get`` that doesn't bypass string interpolation."""
409
        try:
410
            return self[key]
411
        except KeyError:
412
            return default
413
414
    def update(self, indict):
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
415
        """
416
        A version of update that uses our ``__setitem__``.
417
        """
1185.12.49 by Aaron Bentley
Switched to ConfigObj
418
        for entry in indict:
419
            self[entry] = indict[entry]
420
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
421
1185.12.49 by Aaron Bentley
Switched to ConfigObj
422
    def pop(self, key, *args):
423
        """ """
424
        val = dict.pop(self, key, *args)
425
        if key in self.scalars:
426
            del self.comments[key]
427
            del self.inline_comments[key]
428
            self.scalars.remove(key)
429
        elif key in self.sections:
430
            del self.comments[key]
431
            del self.inline_comments[key]
432
            self.sections.remove(key)
433
        if self.main.interpolation and isinstance(val, StringTypes):
434
            return self._interpolate(val)
435
        return val
436
437
    def popitem(self):
438
        """Pops the first (key,val)"""
439
        sequence = (self.scalars + self.sections)
440
        if not sequence:
441
            raise KeyError, ": 'popitem(): dictionary is empty'"
442
        key = sequence[0]
443
        val =  self[key]
444
        del self[key]
445
        return key, val
446
447
    def clear(self):
448
        """
449
        A version of clear that also affects scalars/sections
450
        Also clears comments and configspec.
451
        
452
        Leaves other attributes alone :
453
            depth/main/parent are not affected
454
        """
455
        dict.clear(self)
456
        self.scalars = []
457
        self.sections = []
458
        self.comments = {}
459
        self.inline_comments = {}
460
        self.configspec = {}
461
462
    def setdefault(self, key, default=None):
463
        """A version of setdefault that sets sequence if appropriate."""
464
        try:
465
            return self[key]
466
        except KeyError:
467
            self[key] = default
468
            return self[key]
469
470
    def items(self):
471
        """ """
472
        return zip((self.scalars + self.sections), self.values())
473
474
    def keys(self):
475
        """ """
476
        return (self.scalars + self.sections)
477
478
    def values(self):
479
        """ """
480
        return [self[key] for key in (self.scalars + self.sections)]
481
482
    def iteritems(self):
483
        """ """
484
        return iter(self.items())
485
486
    def iterkeys(self):
487
        """ """
488
        return iter((self.scalars + self.sections))
489
490
    __iter__ = iterkeys
491
492
    def itervalues(self):
493
        """ """
494
        return iter(self.values())
495
496
    def __repr__(self):
497
        return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(self[key])))
498
            for key in (self.scalars + self.sections)])
499
500
    __str__ = __repr__
501
502
    # Extra methods - not in a normal dictionary
503
504
    def dict(self):
505
        """
506
        Return a deepcopy of self as a dictionary.
507
        
508
        All members that are ``Section`` instances are recursively turned to
509
        ordinary dictionaries - by calling their ``dict`` method.
510
        
511
        >>> n = a.dict()
512
        >>> n == a
513
        1
514
        >>> n is a
515
        0
516
        """
517
        newdict = {}
518
        for entry in self:
519
            this_entry = self[entry]
520
            if isinstance(this_entry, Section):
521
                this_entry = this_entry.dict()
522
            elif isinstance(this_entry, (list, tuple)):
523
                # create a copy rather than a reference
524
                this_entry = list(this_entry)
525
            newdict[entry] = this_entry
526
        return newdict
527
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
528
    def merge(self, indict):
529
        """
530
        A recursive update - useful for merging config files.
531
        
532
        >>> a = '''[section1]
533
        ...     option1 = True
534
        ...     [[subsection]]
535
        ...     more_options = False
536
        ...     # end of file'''.splitlines()
537
        >>> b = '''# File is user.ini
538
        ...     [section1]
539
        ...     option1 = False
540
        ...     # end of file'''.splitlines()
541
        >>> c1 = ConfigObj(b)
542
        >>> c2 = ConfigObj(a)
543
        >>> c2.merge(c1)
544
        >>> c2
545
        {'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}}
546
        """
547
        for key, val in indict.items():
548
            if (key in self and isinstance(self[key], dict) and
549
                                isinstance(val, dict)):
550
                self[key].merge(val)
551
            else:   
552
                self[key] = val
553
1185.12.49 by Aaron Bentley
Switched to ConfigObj
554
    def rename(self, oldkey, newkey):
555
        """
556
        Change a keyname to another, without changing position in sequence.
557
        
558
        Implemented so that transformations can be made on keys,
559
        as well as on values. (used by encode and decode)
560
        
561
        Also renames comments.
562
        """
563
        if oldkey in self.scalars:
564
            the_list = self.scalars
565
        elif oldkey in self.sections:
566
            the_list = self.sections
567
        else:
568
            raise KeyError, 'Key "%s" not found.' % oldkey
569
        pos = the_list.index(oldkey)
570
        #
571
        val = self[oldkey]
572
        dict.__delitem__(self, oldkey)
573
        dict.__setitem__(self, newkey, val)
574
        the_list.remove(oldkey)
575
        the_list.insert(pos, newkey)
576
        comm = self.comments[oldkey]
577
        inline_comment = self.inline_comments[oldkey]
578
        del self.comments[oldkey]
579
        del self.inline_comments[oldkey]
580
        self.comments[newkey] = comm
581
        self.inline_comments[newkey] = inline_comment
582
583
    def walk(self, function, raise_errors=True,
584
            call_on_sections=False, **keywargs):
585
        """
586
        Walk every member and call a function on the keyword and value.
587
        
588
        Return a dictionary of the return values
589
        
590
        If the function raises an exception, raise the errror
591
        unless ``raise_errors=False``, in which case set the return value to
592
        ``False``.
593
        
594
        Any unrecognised keyword arguments you pass to walk, will be pased on
595
        to the function you pass in.
596
        
597
        Note: if ``call_on_sections`` is ``True`` then - on encountering a
598
        subsection, *first* the function is called for the *whole* subsection,
599
        and then recurses into it's members. This means your function must be
600
        able to handle strings, dictionaries and lists. This allows you
601
        to change the key of subsections as well as for ordinary members. The
602
        return value when called on the whole subsection has to be discarded.
603
        
604
        See  the encode and decode methods for examples, including functions.
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
605
        
606
        .. caution::
607
        
608
            You can use ``walk`` to transform the names of members of a section
609
            but you mustn't add or delete members.
610
        
611
        >>> config = '''[XXXXsection]
612
        ... XXXXkey = XXXXvalue'''.splitlines()
613
        >>> cfg = ConfigObj(config)
614
        >>> cfg
615
        {'XXXXsection': {'XXXXkey': 'XXXXvalue'}}
616
        >>> def transform(section, key):
617
        ...     val = section[key]
618
        ...     newkey = key.replace('XXXX', 'CLIENT1')
619
        ...     section.rename(key, newkey)
620
        ...     if isinstance(val, (tuple, list, dict)):
621
        ...         pass
622
        ...     else:
623
        ...         val = val.replace('XXXX', 'CLIENT1')
624
        ...         section[newkey] = val
625
        >>> cfg.walk(transform, call_on_sections=True)
626
        {'CLIENT1section': {'CLIENT1key': None}}
627
        >>> cfg
628
        {'CLIENT1section': {'CLIENT1key': 'CLIENT1value'}}
1185.12.49 by Aaron Bentley
Switched to ConfigObj
629
        """
630
        out = {}
631
        # scalars first
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
632
        for i in range(len(self.scalars)):
633
            entry = self.scalars[i]
1185.12.49 by Aaron Bentley
Switched to ConfigObj
634
            try:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
635
                val = function(self, entry, **keywargs)
636
                # bound again in case name has changed
637
                entry = self.scalars[i]
638
                out[entry] = val
1185.12.49 by Aaron Bentley
Switched to ConfigObj
639
            except Exception:
640
                if raise_errors:
641
                    raise
642
                else:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
643
                    entry = self.scalars[i]
1185.12.49 by Aaron Bentley
Switched to ConfigObj
644
                    out[entry] = False
645
        # then sections
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
646
        for i in range(len(self.sections)):
647
            entry = self.sections[i]
1185.12.49 by Aaron Bentley
Switched to ConfigObj
648
            if call_on_sections:
649
                try:
650
                    function(self, entry, **keywargs)
651
                except Exception:
652
                    if raise_errors:
653
                        raise
654
                    else:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
655
                        entry = self.sections[i]
1185.12.49 by Aaron Bentley
Switched to ConfigObj
656
                        out[entry] = False
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
657
                # bound again in case name has changed
658
                entry = self.sections[i]
1185.12.49 by Aaron Bentley
Switched to ConfigObj
659
            # previous result is discarded
660
            out[entry] = self[entry].walk(
661
                function,
662
                raise_errors=raise_errors,
663
                call_on_sections=call_on_sections,
664
                **keywargs)
665
        return out
666
667
    def decode(self, encoding):
668
        """
669
        Decode all strings and values to unicode, using the specified encoding.
670
        
671
        Works with subsections and list values.
672
        
673
        Uses the ``walk`` method.
674
        
675
        Testing ``encode`` and ``decode``.
676
        >>> m = ConfigObj(a)
677
        >>> m.decode('ascii')
678
        >>> def testuni(val):
679
        ...     for entry in val:
680
        ...         if not isinstance(entry, unicode):
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
681
        ...             sys.stderr.write(type(entry))
682
        ...             sys.stderr.write('\n')
1185.12.49 by Aaron Bentley
Switched to ConfigObj
683
        ...             raise AssertionError, 'decode failed.'
684
        ...         if isinstance(val[entry], dict):
685
        ...             testuni(val[entry])
686
        ...         elif not isinstance(val[entry], unicode):
687
        ...             raise AssertionError, 'decode failed.'
688
        >>> testuni(m)
689
        >>> m.encode('ascii')
690
        >>> a == m
691
        1
692
        """
693
        def decode(section, key, encoding=encoding):
694
            """ """
695
            val = section[key]
696
            if isinstance(val, (list, tuple)):
697
                newval = []
698
                for entry in val:
699
                    newval.append(entry.decode(encoding))
700
            elif isinstance(val, dict):
701
                newval = val
702
            else:
703
                newval = val.decode(encoding)
704
            newkey = key.decode(encoding)
705
            section.rename(key, newkey)
706
            section[newkey] = newval
707
        # using ``call_on_sections`` allows us to modify section names
708
        self.walk(decode, call_on_sections=True)
709
710
    def encode(self, encoding):
711
        """
712
        Encode all strings and values from unicode,
713
        using the specified encoding.
714
        
715
        Works with subsections and list values.
716
        Uses the ``walk`` method.
717
        """
718
        def encode(section, key, encoding=encoding):
719
            """ """
720
            val = section[key]
721
            if isinstance(val, (list, tuple)):
722
                newval = []
723
                for entry in val:
724
                    newval.append(entry.encode(encoding))
725
            elif isinstance(val, dict):
726
                newval = val
727
            else:
728
                newval = val.encode(encoding)
729
            newkey = key.encode(encoding)
730
            section.rename(key, newkey)
731
            section[newkey] = newval
732
        self.walk(encode, call_on_sections=True)
733
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
734
    def istrue(self, key):
735
        """A deprecated version of ``as_bool``."""
736
        warn('use of ``istrue`` is deprecated. Use ``as_bool`` method '
737
                'instead.', DeprecationWarning)
738
        return self.as_bool(key)
739
740
    def as_bool(self, key):
741
        """
742
        Accepts a key as input. The corresponding value must be a string or
743
        the objects (``True`` or 1) or (``False`` or 0). We allow 0 and 1 to
744
        retain compatibility with Python 2.2.
745
        
746
        If the string is one of  ``True``, ``On``, ``Yes``, or ``1`` it returns 
747
        ``True``.
748
        
749
        If the string is one of  ``False``, ``Off``, ``No``, or ``0`` it returns 
750
        ``False``.
751
        
752
        ``as_bool`` is not case sensitive.
753
        
754
        Any other input will raise a ``ValueError``.
755
        
756
        >>> a = ConfigObj()
757
        >>> a['a'] = 'fish'
758
        >>> a.as_bool('a')
759
        Traceback (most recent call last):
760
        ValueError: Value "fish" is neither True nor False
761
        >>> a['b'] = 'True'
762
        >>> a.as_bool('b')
763
        1
764
        >>> a['b'] = 'off'
765
        >>> a.as_bool('b')
766
        0
767
        """
768
        val = self[key]
769
        if val == True:
770
            return True
771
        elif val == False:
772
            return False
773
        else:
774
            try:
775
                if not isinstance(val, StringTypes):
776
                    raise KeyError
777
                else:
778
                    return self.main._bools[val.lower()]
779
            except KeyError:
780
                raise ValueError('Value "%s" is neither True nor False' % val)
781
782
    def as_int(self, key):
783
        """
784
        A convenience method which coerces the specified value to an integer.
785
        
786
        If the value is an invalid literal for ``int``, a ``ValueError`` will
787
        be raised.
788
        
789
        >>> a = ConfigObj()
790
        >>> a['a'] = 'fish'
791
        >>> a.as_int('a')
792
        Traceback (most recent call last):
793
        ValueError: invalid literal for int(): fish
794
        >>> a['b'] = '1'
795
        >>> a.as_int('b')
796
        1
797
        >>> a['b'] = '3.2'
798
        >>> a.as_int('b')
799
        Traceback (most recent call last):
800
        ValueError: invalid literal for int(): 3.2
801
        """
802
        return int(self[key])
803
804
    def as_float(self, key):
805
        """
806
        A convenience method which coerces the specified value to a float.
807
        
808
        If the value is an invalid literal for ``float``, a ``ValueError`` will
809
        be raised.
810
        
811
        >>> a = ConfigObj()
812
        >>> a['a'] = 'fish'
813
        >>> a.as_float('a')
814
        Traceback (most recent call last):
815
        ValueError: invalid literal for float(): fish
816
        >>> a['b'] = '1'
817
        >>> a.as_float('b')
818
        1.0
819
        >>> a['b'] = '3.2'
820
        >>> a.as_float('b')
821
        3.2000000000000002
822
        """
823
        return float(self[key])
824
    
825
1185.12.49 by Aaron Bentley
Switched to ConfigObj
826
class ConfigObj(Section):
827
    """
828
    An object to read, create, and write config files.
829
    
830
    Testing with duplicate keys and sections.
831
    
832
    >>> c = '''
833
    ... [hello]
834
    ... member = value
835
    ... [hello again]
836
    ... member = value
837
    ... [ "hello" ]
838
    ... member = value
839
    ... '''
840
    >>> ConfigObj(c.split('\\n'), raise_errors = True)
841
    Traceback (most recent call last):
842
    DuplicateError: Duplicate section name at line 5.
843
    
844
    >>> d = '''
845
    ... [hello]
846
    ... member = value
847
    ... [hello again]
848
    ... member1 = value
849
    ... member2 = value
850
    ... 'member1' = value
851
    ... [ "and again" ]
852
    ... member = value
853
    ... '''
854
    >>> ConfigObj(d.split('\\n'), raise_errors = True)
855
    Traceback (most recent call last):
856
    DuplicateError: Duplicate keyword name at line 6.
857
    """
858
859
    _keyword = re.compile(r'''^ # line start
860
        (\s*)                   # indentation
861
        (                       # keyword
862
            (?:".*?")|          # double quotes
863
            (?:'.*?')|          # single quotes
864
            (?:[^'"=].*?)       # no quotes
865
        )
866
        \s*=\s*                 # divider
867
        (.*)                    # value (including list values and comments)
868
        $   # line end
869
        ''',
870
        re.VERBOSE)
871
872
    _sectionmarker = re.compile(r'''^
873
        (\s*)                     # 1: indentation
874
        ((?:\[\s*)+)              # 2: section marker open
875
        (                         # 3: section name open
876
            (?:"\s*\S.*?\s*")|    # at least one non-space with double quotes
877
            (?:'\s*\S.*?\s*')|    # at least one non-space with single quotes
878
            (?:[^'"\s].*?)        # at least one non-space unquoted
879
        )                         # section name close
880
        ((?:\s*\])+)              # 4: section marker close
881
        \s*(\#.*)?                # 5: optional comment
882
        $''',
883
        re.VERBOSE)
884
885
    # this regexp pulls list values out as a single string
886
    # or single values and comments
887
    _valueexp = re.compile(r'''^
888
        (?:
889
            (?:
890
                (
891
                    (?:
892
                        (?:
893
                            (?:".*?")|              # double quotes
894
                            (?:'.*?')|              # single quotes
895
                            (?:[^'",\#][^,\#]*?)       # unquoted
896
                        )
897
                        \s*,\s*                     # comma
898
                    )*      # match all list items ending in a comma (if any)
899
                )
900
                (
901
                    (?:".*?")|                      # double quotes
902
                    (?:'.*?')|                      # single quotes
903
                    (?:[^'",\#\s][^,]*?)             # unquoted
904
                )?          # last item in a list - or string value
905
            )|
906
            (,)             # alternatively a single comma - empty list
907
        )
908
        \s*(\#.*)?          # optional comment
909
        $''',
910
        re.VERBOSE)
911
912
    # use findall to get the members of a list value
913
    _listvalueexp = re.compile(r'''
914
        (
915
            (?:".*?")|          # double quotes
916
            (?:'.*?')|          # single quotes
917
            (?:[^'",\#].*?)       # unquoted
918
        )
919
        \s*,\s*                 # comma
920
        ''',
921
        re.VERBOSE)
922
923
    # this regexp is used for the value
924
    # when lists are switched off
925
    _nolistvalue = re.compile(r'''^
926
        (
927
            (?:".*?")|          # double quotes
928
            (?:'.*?')|          # single quotes
929
            (?:[^'"\#].*?)      # unquoted
930
        )
931
        \s*(\#.*)?              # optional comment
932
        $''',
933
        re.VERBOSE)
934
935
    # regexes for finding triple quoted values on one line
936
    _single_line_single = re.compile(r"^'''(.*?)'''\s*(#.*)?$")
937
    _single_line_double = re.compile(r'^"""(.*?)"""\s*(#.*)?$')
938
    _multi_line_single = re.compile(r"^(.*?)'''\s*(#.*)?$")
939
    _multi_line_double = re.compile(r'^(.*?)"""\s*(#.*)?$')
940
941
    _triple_quote = {
942
        "'''": (_single_line_single, _multi_line_single),
943
        '"""': (_single_line_double, _multi_line_double),
944
    }
945
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
946
    # Used by the ``istrue`` Section method
947
    _bools = {
948
        'yes': True, 'no': False,
949
        'on': True, 'off': False,
950
        '1': True, '0': False,
951
        'true': True, 'false': False,
952
        }
953
1185.12.49 by Aaron Bentley
Switched to ConfigObj
954
    def __init__(self, infile=None, options=None, **kwargs):
955
        """
956
        Parse or create a config file object.
957
        
958
        ``ConfigObj(infile=None, options=None, **kwargs)``
959
        """
960
        if infile is None:
961
            infile = []
962
        if options is None:
963
            options = {}
964
        # keyword arguments take precedence over an options dictionary
965
        options.update(kwargs)
966
        # init the superclass
967
        Section.__init__(self, self, 0, self)
968
        #
969
        defaults = OPTION_DEFAULTS.copy()
970
        for entry in options.keys():
971
            if entry not in defaults.keys():
972
                raise TypeError, 'Unrecognised option "%s".' % entry
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
973
        # TODO: check the values too.
974
        #
975
        # Add any explicit options to the defaults
1185.12.49 by Aaron Bentley
Switched to ConfigObj
976
        defaults.update(options)
977
        #
978
        # initialise a few variables
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
979
        self.filename = None
1185.12.49 by Aaron Bentley
Switched to ConfigObj
980
        self._errors = []
981
        self.raise_errors = defaults['raise_errors']
982
        self.interpolation = defaults['interpolation']
983
        self.list_values = defaults['list_values']
984
        self.create_empty = defaults['create_empty']
985
        self.file_error = defaults['file_error']
986
        self.stringify = defaults['stringify']
987
        self.indent_type = defaults['indent_type']
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
988
        self.encoding = defaults['encoding']
989
        self.default_encoding = defaults['default_encoding']
990
        self.BOM = False
991
        self.newlines = None
1185.12.49 by Aaron Bentley
Switched to ConfigObj
992
        #
993
        self.initial_comment = []
994
        self.final_comment = []
995
        #
996
        if isinstance(infile, StringTypes):
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
997
            self.filename = infile
998
            if os.path.isfile(infile):
999
                infile = open(infile).read() or []
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1000
            elif self.file_error:
1001
                # raise an error if the file doesn't exist
1002
                raise IOError, 'Config file not found: "%s".' % self.filename
1003
            else:
1004
                # file doesn't already exist
1005
                if self.create_empty:
1006
                    # this is a good test that the filename specified
1007
                    # isn't impossible - like on a non existent device
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1008
                    h = open(infile, 'w')
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1009
                    h.write('')
1010
                    h.close()
1011
                infile = []
1012
        elif isinstance(infile, (list, tuple)):
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1013
            infile = list(infile)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1014
        elif isinstance(infile, dict):
1015
            # initialise self
1016
            # the Section class handles creating subsections
1017
            if isinstance(infile, ConfigObj):
1018
                # get a copy of our ConfigObj
1019
                infile = infile.dict()
1020
            for entry in infile:
1021
                self[entry] = infile[entry]
1022
            del self._errors
1023
            if defaults['configspec'] is not None:
1024
                self._handle_configspec(defaults['configspec'])
1025
            else:
1026
                self.configspec = None
1027
            return
1963.2.6 by Robey Pointer
pychecker is on crack; go back to using 'is None'.
1028
        elif getattr(infile, 'read', None) is not None:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1029
            # This supports file like objects
1030
            infile = infile.read() or []
1031
            # needs splitting into lines - but needs doing *after* decoding
1032
            # in case it's not an 8 bit encoding
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1033
        else:
1034
            raise TypeError, ('infile must be a filename,'
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1035
                ' file like object, or list of lines.')
1036
        #
1037
        if infile:
1038
            # don't do it for the empty ConfigObj
1039
            infile = self._handle_bom(infile)
1040
            # infile is now *always* a list
1041
            #
1042
            # Set the newlines attribute (first line ending it finds)
1043
            # and strip trailing '\n' or '\r' from lines
1044
            for line in infile:
1045
                if (not line) or (line[-1] not in '\r\n'):
1046
                    continue
1047
                for end in ('\r\n', '\n', '\r'):
1048
                    if line.endswith(end):
1049
                        self.newlines = end
1050
                        break
1051
                break
1052
            infile = [line.rstrip('\r\n') for line in infile]
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1053
        #
1054
        self._parse(infile)
1055
        # if we had any errors, now is the time to raise them
1056
        if self._errors:
1057
            error = ConfigObjError("Parsing failed.")
1058
            # set the errors attribute; it's a list of tuples:
1059
            # (error_type, message, line_number)
1060
            error.errors = self._errors
1061
            # set the config attribute
1062
            error.config = self
1063
            raise error
1064
        # delete private attributes
1065
        del self._errors
1066
        #
1067
        if defaults['configspec'] is None:
1068
            self.configspec = None
1069
        else:
1070
            self._handle_configspec(defaults['configspec'])
1071
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1072
    def _handle_bom(self, infile):
1073
        """
1074
        Handle any BOM, and decode if necessary.
1075
        
1076
        If an encoding is specified, that *must* be used - but the BOM should
1077
        still be removed (and the BOM attribute set).
1078
        
1079
        (If the encoding is wrongly specified, then a BOM for an alternative
1080
        encoding won't be discovered or removed.)
1081
        
1082
        If an encoding is not specified, UTF8 or UTF16 BOM will be detected and
1083
        removed. The BOM attribute will be set. UTF16 will be decoded to
1084
        unicode.
1085
        
1086
        NOTE: This method must not be called with an empty ``infile``.
1087
        
1088
        Specifying the *wrong* encoding is likely to cause a
1089
        ``UnicodeDecodeError``.
1090
        
1091
        ``infile`` must always be returned as a list of lines, but may be
1092
        passed in as a single string.
1093
        """
1094
        if ((self.encoding is not None) and
1095
            (self.encoding.lower() not in BOM_LIST)):
1096
            # No need to check for a BOM
1097
            # encoding specified doesn't have one
1098
            # just decode
1099
            return self._decode(infile, self.encoding)
1100
        #
1101
        if isinstance(infile, (list, tuple)):
1102
            line = infile[0]
1103
        else:
1104
            line = infile
1105
        if self.encoding is not None:
1106
            # encoding explicitly supplied
1107
            # And it could have an associated BOM
1108
            # TODO: if encoding is just UTF16 - we ought to check for both
1109
            # TODO: big endian and little endian versions.
1110
            enc = BOM_LIST[self.encoding.lower()]
1111
            if enc == 'utf_16':
1112
                # For UTF16 we try big endian and little endian
1113
                for BOM, (encoding, final_encoding) in BOMS.items():
1114
                    if not final_encoding:
1115
                        # skip UTF8
1116
                        continue
1117
                    if infile.startswith(BOM):
1118
                        ### BOM discovered
1119
                        ##self.BOM = True
1120
                        # Don't need to remove BOM
1121
                        return self._decode(infile, encoding)
1122
                #
1123
                # If we get this far, will *probably* raise a DecodeError
1124
                # As it doesn't appear to start with a BOM
1125
                return self._decode(infile, self.encoding)
1126
            #
1127
            # Must be UTF8
1128
            BOM = BOM_SET[enc]
1129
            if not line.startswith(BOM):
1130
                return self._decode(infile, self.encoding)
1131
            #
1132
            newline = line[len(BOM):]
1133
            #
1134
            # BOM removed
1135
            if isinstance(infile, (list, tuple)):
1136
                infile[0] = newline
1137
            else:
1138
                infile = newline
1139
            self.BOM = True
1140
            return self._decode(infile, self.encoding)
1141
        #
1142
        # No encoding specified - so we need to check for UTF8/UTF16
1143
        for BOM, (encoding, final_encoding) in BOMS.items():
1144
            if not line.startswith(BOM):
1145
                continue
1146
            else:
1147
                # BOM discovered
1148
                self.encoding = final_encoding
1149
                if not final_encoding:
1150
                    self.BOM = True
1151
                    # UTF8
1152
                    # remove BOM
1153
                    newline = line[len(BOM):]
1154
                    if isinstance(infile, (list, tuple)):
1155
                        infile[0] = newline
1156
                    else:
1157
                        infile = newline
1158
                    # UTF8 - don't decode
1159
                    if isinstance(infile, StringTypes):
1160
                        return infile.splitlines(True)
1161
                    else:
1162
                        return infile
1163
                # UTF16 - have to decode
1164
                return self._decode(infile, encoding)
1165
        #
1166
        # No BOM discovered and no encoding specified, just return
1167
        if isinstance(infile, StringTypes):
1168
            # infile read from a file will be a single string
1169
            return infile.splitlines(True)
1170
        else:
1171
            return infile
1172
1173
    def _a_to_u(self, string):
1174
        """Decode ascii strings to unicode if a self.encoding is specified."""
1175
        if not self.encoding:
1176
            return string
1177
        else:
1178
            return string.decode('ascii')
1179
1180
    def _decode(self, infile, encoding):
1181
        """
1182
        Decode infile to unicode. Using the specified encoding.
1183
        
1184
        if is a string, it also needs converting to a list.
1185
        """
1186
        if isinstance(infile, StringTypes):
1187
            # can't be unicode
1188
            # NOTE: Could raise a ``UnicodeDecodeError``
1189
            return infile.decode(encoding).splitlines(True)
1190
        for i, line in enumerate(infile):
1191
            if not isinstance(line, unicode):
1192
                # NOTE: The isinstance test here handles mixed lists of unicode/string
1193
                # NOTE: But the decode will break on any non-string values
1194
                # NOTE: Or could raise a ``UnicodeDecodeError``
1195
                infile[i] = line.decode(encoding)
1196
        return infile
1197
1198
    def _decode_element(self, line):
1199
        """Decode element to unicode if necessary."""
1200
        if not self.encoding:
1201
            return line
1202
        if isinstance(line, str) and self.default_encoding:
1203
            return line.decode(self.default_encoding)
1204
        return line
1205
1206
    def _str(self, value):
1207
        """
1208
        Used by ``stringify`` within validate, to turn non-string values
1209
        into strings.
1210
        """
1211
        if not isinstance(value, StringTypes):
1212
            return str(value)
1213
        else:
1214
            return value
1215
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1216
    def _parse(self, infile):
1217
        """
1218
        Actually parse the config file
1219
        
1220
        Testing Interpolation
1221
        
1222
        >>> c = ConfigObj()
1223
        >>> c['DEFAULT'] = {
1224
        ...     'b': 'goodbye',
1225
        ...     'userdir': 'c:\\\\home',
1226
        ...     'c': '%(d)s',
1227
        ...     'd': '%(c)s'
1228
        ... }
1229
        >>> c['section'] = {
1230
        ...     'a': '%(datadir)s\\\\some path\\\\file.py',
1231
        ...     'b': '%(userdir)s\\\\some path\\\\file.py',
1232
        ...     'c': 'Yo %(a)s',
1233
        ...     'd': '%(not_here)s',
1234
        ...     'e': '%(c)s',
1235
        ... }
1236
        >>> c['section']['DEFAULT'] = {
1237
        ...     'datadir': 'c:\\\\silly_test',
1238
        ...     'a': 'hello - %(b)s',
1239
        ... }
1240
        >>> c['section']['a'] == 'c:\\\\silly_test\\\\some path\\\\file.py'
1241
        1
1242
        >>> c['section']['b'] == 'c:\\\\home\\\\some path\\\\file.py'
1243
        1
1244
        >>> c['section']['c'] == 'Yo hello - goodbye'
1245
        1
1246
        
1247
        Switching Interpolation Off
1248
        
1249
        >>> c.interpolation = False
1250
        >>> c['section']['a'] == '%(datadir)s\\\\some path\\\\file.py'
1251
        1
1252
        >>> c['section']['b'] == '%(userdir)s\\\\some path\\\\file.py'
1253
        1
1254
        >>> c['section']['c'] == 'Yo %(a)s'
1255
        1
1256
        
1257
        Testing the interpolation errors.
1258
        
1259
        >>> c.interpolation = True
1260
        >>> c['section']['d']
1261
        Traceback (most recent call last):
1262
        MissingInterpolationOption: missing option "not_here" in interpolation.
1263
        >>> c['section']['e']
1264
        Traceback (most recent call last):
1265
        InterpolationDepthError: max interpolation depth exceeded in value "%(c)s".
1266
        
1267
        Testing our quoting.
1268
        
1269
        >>> i._quote('\"""\'\'\'')
1270
        Traceback (most recent call last):
1271
        SyntaxError: EOF while scanning triple-quoted string
1272
        >>> try:
1273
        ...     i._quote('\\n', multiline=False)
1274
        ... except ConfigObjError, e:
1275
        ...    e.msg
1276
        'Value "\\n" cannot be safely quoted.'
1277
        >>> k._quote(' "\' ', multiline=False)
1278
        Traceback (most recent call last):
1279
        SyntaxError: EOL while scanning single-quoted string
1280
        
1281
        Testing with "stringify" off.
1282
        >>> c.stringify = False
1283
        >>> c['test'] = 1
1284
        Traceback (most recent call last):
1285
        TypeError: Value is not a string "1".
1286
        """
1287
        comment_list = []
1288
        done_start = False
1289
        this_section = self
1290
        maxline = len(infile) - 1
1291
        cur_index = -1
1292
        reset_comment = False
1293
        while cur_index < maxline:
1294
            if reset_comment:
1295
                comment_list = []
1296
            cur_index += 1
1297
            line = infile[cur_index]
1298
            sline = line.strip()
1299
            # do we have anything on the line ?
1300
            if not sline or sline.startswith('#'):
1301
                reset_comment = False
1302
                comment_list.append(line)
1303
                continue
1304
            if not done_start:
1305
                # preserve initial comment
1306
                self.initial_comment = comment_list
1307
                comment_list = []
1308
                done_start = True
1309
            reset_comment = True
1310
            # first we check if it's a section marker
1311
            mat = self._sectionmarker.match(line)
2911.6.3 by Blake Winton
Implemented suggestions from John Arbash Meinel.
1312
##            sys.stderr.write('%s %s\n' % (sline, mat))
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1313
            if mat is not None:
1314
                # is a section line
1315
                (indent, sect_open, sect_name, sect_close, comment) = (
1316
                    mat.groups())
1317
                if indent and (self.indent_type is None):
1318
                    self.indent_type = indent[0]
1319
                cur_depth = sect_open.count('[')
1320
                if cur_depth != sect_close.count(']'):
1321
                    self._handle_error(
1322
                        "Cannot compute the section depth at line %s.",
1323
                        NestingError, infile, cur_index)
1324
                    continue
1325
                if cur_depth < this_section.depth:
1326
                    # the new section is dropping back to a previous level
1327
                    try:
1328
                        parent = self._match_depth(
1329
                            this_section,
1330
                            cur_depth).parent
1331
                    except SyntaxError:
1332
                        self._handle_error(
1333
                            "Cannot compute nesting level at line %s.",
1334
                            NestingError, infile, cur_index)
1335
                        continue
1336
                elif cur_depth == this_section.depth:
1337
                    # the new section is a sibling of the current section
1338
                    parent = this_section.parent
1339
                elif cur_depth == this_section.depth + 1:
1340
                    # the new section is a child the current section
1341
                    parent = this_section
1342
                else:
1343
                    self._handle_error(
1344
                        "Section too nested at line %s.",
1345
                        NestingError, infile, cur_index)
1346
                #
1347
                sect_name = self._unquote(sect_name)
1963.2.1 by Robey Pointer
remove usage of has_key()
1348
                if sect_name in parent:
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
1349
##                    sys.stderr.write(sect_name)
1350
##                    sys.stderr.write('\n')
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1351
                    self._handle_error(
1352
                        'Duplicate section name at line %s.',
1353
                        DuplicateError, infile, cur_index)
1354
                    continue
1355
                # create the new section
1356
                this_section = Section(
1357
                    parent,
1358
                    cur_depth,
1359
                    self,
1360
                    name=sect_name)
1361
                parent[sect_name] = this_section
1362
                parent.inline_comments[sect_name] = comment
1363
                parent.comments[sect_name] = comment_list
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
1364
##                sys.stderr.write(parent[sect_name] is this_section)
1365
##                sys.stderr.write('\n')
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1366
                continue
1367
            #
1368
            # it's not a section marker,
1369
            # so it should be a valid ``key = value`` line
1370
            mat = self._keyword.match(line)
2911.6.3 by Blake Winton
Implemented suggestions from John Arbash Meinel.
1371
##            sys.stderr.write('%s %s\n' % (sline, mat))
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1372
            if mat is not None:
1373
                # is a keyword value
1374
                # value will include any inline comment
1375
                (indent, key, value) = mat.groups()
1376
                if indent and (self.indent_type is None):
1377
                    self.indent_type = indent[0]
1378
                # check for a multiline value
1379
                if value[:3] in ['"""', "'''"]:
1380
                    try:
1381
                        (value, comment, cur_index) = self._multiline(
1382
                            value, infile, cur_index, maxline)
1383
                    except SyntaxError:
1384
                        self._handle_error(
1385
                            'Parse error in value at line %s.',
1386
                            ParseError, infile, cur_index)
1387
                        continue
1388
                else:
1389
                    # extract comment and lists
1390
                    try:
1391
                        (value, comment) = self._handle_value(value)
1392
                    except SyntaxError:
1393
                        self._handle_error(
1394
                            'Parse error in value at line %s.',
1395
                            ParseError, infile, cur_index)
1396
                        continue
1397
                #
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
1398
##                sys.stderr.write(sline)
1399
##                sys.stderr.write('\n')
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1400
                key = self._unquote(key)
1963.2.1 by Robey Pointer
remove usage of has_key()
1401
                if key in this_section:
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1402
                    self._handle_error(
1403
                        'Duplicate keyword name at line %s.',
1404
                        DuplicateError, infile, cur_index)
1405
                    continue
1406
                # add the key
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
1407
##                sys.stderr.write(this_section.name + '\n')
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1408
                this_section[key] = value
1409
                this_section.inline_comments[key] = comment
1410
                this_section.comments[key] = comment_list
2911.6.3 by Blake Winton
Implemented suggestions from John Arbash Meinel.
1411
##                sys.stderr.write('%s %s\n' % (key, this_section[key]))
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1412
##                if this_section.name is not None:
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
1413
##                    sys.stderr.write(this_section + '\n')
1414
##                    sys.stderr.write(this_section.parent + '\n')
1415
##                    sys.stderr.write(this_section.parent[this_section.name])
1416
##                    sys.stderr.write('\n')
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1417
                continue
1418
            #
1419
            # it neither matched as a keyword
1420
            # or a section marker
1421
            self._handle_error(
1422
                'Invalid line at line "%s".',
1423
                ParseError, infile, cur_index)
1424
        if self.indent_type is None:
1425
            # no indentation used, set the type accordingly
1426
            self.indent_type = ''
1427
        # preserve the final comment
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1428
        if not self and not self.initial_comment:
1429
            self.initial_comment = comment_list
1430
        else:
1431
            self.final_comment = comment_list
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1432
1433
    def _match_depth(self, sect, depth):
1434
        """
1435
        Given a section and a depth level, walk back through the sections
1436
        parents to see if the depth level matches a previous section.
1437
        
1438
        Return a reference to the right section,
1439
        or raise a SyntaxError.
1440
        """
1441
        while depth < sect.depth:
1442
            if sect is sect.parent:
1443
                # we've reached the top level already
1444
                raise SyntaxError
1445
            sect = sect.parent
1446
        if sect.depth == depth:
1447
            return sect
1448
        # shouldn't get here
1449
        raise SyntaxError
1450
1451
    def _handle_error(self, text, ErrorClass, infile, cur_index):
1452
        """
1453
        Handle an error according to the error settings.
1454
        
1455
        Either raise the error or store it.
1456
        The error will have occured at ``cur_index``
1457
        """
1458
        line = infile[cur_index]
2900.1.2 by Vincent Ladeuil
Fix 149019 by using a proper line number when reporting errors.
1459
        cur_index += 1
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1460
        message = text % cur_index
1461
        error = ErrorClass(message, cur_index, line)
1462
        if self.raise_errors:
1463
            # raise the error - parsing stops here
1464
            raise error
1465
        # store the error
1466
        # reraise when parsing has finished
1467
        self._errors.append(error)
1468
1469
    def _unquote(self, value):
1470
        """Return an unquoted version of a value"""
1471
        if (value[0] == value[-1]) and (value[0] in ('"', "'")):
1472
            value = value[1:-1]
1473
        return value
1474
1475
    def _quote(self, value, multiline=True):
1476
        """
1477
        Return a safely quoted version of a value.
1478
        
1479
        Raise a ConfigObjError if the value cannot be safely quoted.
1480
        If multiline is ``True`` (default) then use triple quotes
1481
        if necessary.
1482
        
1483
        Don't quote values that don't need it.
1484
        Recursively quote members of a list and return a comma joined list.
1485
        Multiline is ``False`` for lists.
1486
        Obey list syntax for empty and single member lists.
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1487
        
1488
        If ``list_values=False`` then the value is only quoted if it contains
1489
        a ``\n`` (is multiline).
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1490
        """
1491
        if isinstance(value, (list, tuple)):
1492
            if not value:
1493
                return ','
1494
            elif len(value) == 1:
1495
                return self._quote(value[0], multiline=False) + ','
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1496
            return ', '.join([self._quote(val, multiline=False)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1497
                for val in value])
1498
        if not isinstance(value, StringTypes):
1499
            if self.stringify:
1500
                value = str(value)
1501
            else:
1502
                raise TypeError, 'Value "%s" is not a string.' % value
1503
        squot = "'%s'"
1504
        dquot = '"%s"'
1505
        noquot = "%s"
1506
        wspace_plus = ' \r\t\n\v\t\'"'
1507
        tsquot = '"""%s"""'
1508
        tdquot = "'''%s'''"
1509
        if not value:
1510
            return '""'
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1511
        if (not self.list_values and '\n' not in value) or not (multiline and
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1512
                ((("'" in value) and ('"' in value)) or ('\n' in value))):
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1513
            if not self.list_values:
1514
                # we don't quote if ``list_values=False``
1515
                quot = noquot
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1516
            # for normal values either single or double quotes will do
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1517
            elif '\n' in value:
1518
                # will only happen if multiline is off - e.g. '\n' in key
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1519
                raise ConfigObjError, ('Value "%s" cannot be safely quoted.' %
1520
                    value)
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1521
            elif ((value[0] not in wspace_plus) and
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1522
                    (value[-1] not in wspace_plus) and
1523
                    (',' not in value)):
1524
                quot = noquot
1525
            else:
1526
                if ("'" in value) and ('"' in value):
1527
                    raise ConfigObjError, (
1528
                        'Value "%s" cannot be safely quoted.' % value)
1529
                elif '"' in value:
1530
                    quot = squot
1531
                else:
1532
                    quot = dquot
1533
        else:
1534
            # if value has '\n' or "'" *and* '"', it will need triple quotes
1535
            if (value.find('"""') != -1) and (value.find("'''") != -1):
1536
                raise ConfigObjError, (
1537
                    'Value "%s" cannot be safely quoted.' % value)
1538
            if value.find('"""') == -1:
1539
                quot = tdquot
1540
            else:
1541
                quot = tsquot
1542
        return quot % value
1543
1544
    def _handle_value(self, value):
1545
        """
1546
        Given a value string, unquote, remove comment,
1547
        handle lists. (including empty and single member lists)
1548
        
1549
        Testing list values.
1550
        
1551
        >>> testconfig3 = '''
1552
        ... a = ,
1553
        ... b = test,
1554
        ... c = test1, test2   , test3
1555
        ... d = test1, test2, test3,
1556
        ... '''
1557
        >>> d = ConfigObj(testconfig3.split('\\n'), raise_errors=True)
1558
        >>> d['a'] == []
1559
        1
1560
        >>> d['b'] == ['test']
1561
        1
1562
        >>> d['c'] == ['test1', 'test2', 'test3']
1563
        1
1564
        >>> d['d'] == ['test1', 'test2', 'test3']
1565
        1
1566
        
1567
        Testing with list values off.
1568
        
1569
        >>> e = ConfigObj(
1570
        ...     testconfig3.split('\\n'),
1571
        ...     raise_errors=True,
1572
        ...     list_values=False)
1573
        >>> e['a'] == ','
1574
        1
1575
        >>> e['b'] == 'test,'
1576
        1
1577
        >>> e['c'] == 'test1, test2   , test3'
1578
        1
1579
        >>> e['d'] == 'test1, test2, test3,'
1580
        1
1581
        
1582
        Testing creating from a dictionary.
1583
        
1584
        >>> f = {
1585
        ...     'key1': 'val1',
1586
        ...     'key2': 'val2',
1587
        ...     'section 1': {
1588
        ...         'key1': 'val1',
1589
        ...         'key2': 'val2',
1590
        ...         'section 1b': {
1591
        ...             'key1': 'val1',
1592
        ...             'key2': 'val2',
1593
        ...         },
1594
        ...     },
1595
        ...     'section 2': {
1596
        ...         'key1': 'val1',
1597
        ...         'key2': 'val2',
1598
        ...         'section 2b': {
1599
        ...             'key1': 'val1',
1600
        ...             'key2': 'val2',
1601
        ...         },
1602
        ...     },
1603
        ...      'key3': 'val3',
1604
        ... }
1605
        >>> g = ConfigObj(f)
1606
        >>> f == g
1607
        1
1608
        
1609
        Testing we correctly detect badly built list values (4 of them).
1610
        
1611
        >>> testconfig4 = '''
1612
        ... config = 3,4,,
1613
        ... test = 3,,4
1614
        ... fish = ,,
1615
        ... dummy = ,,hello, goodbye
1616
        ... '''
1617
        >>> try:
1618
        ...     ConfigObj(testconfig4.split('\\n'))
1619
        ... except ConfigObjError, e:
1620
        ...     len(e.errors)
1621
        4
1622
        
1623
        Testing we correctly detect badly quoted values (4 of them).
1624
        
1625
        >>> testconfig5 = '''
1626
        ... config = "hello   # comment
1627
        ... test = 'goodbye
1628
        ... fish = 'goodbye   # comment
1629
        ... dummy = "hello again
1630
        ... '''
1631
        >>> try:
1632
        ...     ConfigObj(testconfig5.split('\\n'))
1633
        ... except ConfigObjError, e:
1634
        ...     len(e.errors)
1635
        4
1636
        """
1637
        # do we look for lists in values ?
1638
        if not self.list_values:
1639
            mat = self._nolistvalue.match(value)
1640
            if mat is None:
1641
                raise SyntaxError
1642
            (value, comment) = mat.groups()
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1643
            # NOTE: we don't unquote here
1644
            return (value, comment)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1645
        mat = self._valueexp.match(value)
1646
        if mat is None:
1647
            # the value is badly constructed, probably badly quoted,
1648
            # or an invalid list
1649
            raise SyntaxError
1650
        (list_values, single, empty_list, comment) = mat.groups()
1651
        if (list_values == '') and (single is None):
1652
            # change this if you want to accept empty values
1653
            raise SyntaxError
1654
        # NOTE: note there is no error handling from here if the regex
1655
        # is wrong: then incorrect values will slip through
1656
        if empty_list is not None:
1657
            # the single comma - meaning an empty list
1658
            return ([], comment)
1659
        if single is not None:
1660
            single = self._unquote(single)
1661
        if list_values == '':
1662
            # not a list value
1663
            return (single, comment)
1664
        the_list = self._listvalueexp.findall(list_values)
1665
        the_list = [self._unquote(val) for val in the_list]
1666
        if single is not None:
1667
            the_list += [single]
1668
        return (the_list, comment)
1669
1670
    def _multiline(self, value, infile, cur_index, maxline):
1671
        """
1672
        Extract the value, where we are in a multiline situation
1673
        
1674
        Testing multiline values.
1675
        
1676
        >>> i == {
1677
        ...     'name4': ' another single line value ',
1678
        ...     'multi section': {
1679
        ...         'name4': '\\n        Well, this is a\\n        multiline '
1680
        ...             'value\\n        ',
1681
        ...         'name2': '\\n        Well, this is a\\n        multiline '
1682
        ...             'value\\n        ',
1683
        ...         'name3': '\\n        Well, this is a\\n        multiline '
1684
        ...             'value\\n        ',
1685
        ...         'name1': '\\n        Well, this is a\\n        multiline '
1686
        ...             'value\\n        ',
1687
        ...     },
1688
        ...     'name2': ' another single line value ',
1689
        ...     'name3': ' a single line value ',
1690
        ...     'name1': ' a single line value ',
1691
        ... }
1692
        1
1693
        """
1694
        quot = value[:3]
1695
        newvalue = value[3:]
1696
        single_line = self._triple_quote[quot][0]
1697
        multi_line = self._triple_quote[quot][1]
1698
        mat = single_line.match(value)
1699
        if mat is not None:
1700
            retval = list(mat.groups())
1701
            retval.append(cur_index)
1702
            return retval
1703
        elif newvalue.find(quot) != -1:
1704
            # somehow the triple quote is missing
1705
            raise SyntaxError
1706
        #
1707
        while cur_index < maxline:
1708
            cur_index += 1
1709
            newvalue += '\n'
1710
            line = infile[cur_index]
1711
            if line.find(quot) == -1:
1712
                newvalue += line
1713
            else:
1714
                # end of multiline, process it
1715
                break
1716
        else:
1717
            # we've got to the end of the config, oops...
1718
            raise SyntaxError
1719
        mat = multi_line.match(line)
1720
        if mat is None:
1721
            # a badly formed line
1722
            raise SyntaxError
1723
        (value, comment) = mat.groups()
1724
        return (newvalue + value, comment, cur_index)
1725
1726
    def _handle_configspec(self, configspec):
1727
        """Parse the configspec."""
1728
        try:
1729
            configspec = ConfigObj(
1730
                configspec,
1731
                raise_errors=True,
1732
                file_error=True,
1733
                list_values=False)
1734
        except ConfigObjError, e:
1735
            # FIXME: Should these errors have a reference
1736
            # to the already parsed ConfigObj ?
1737
            raise ConfigspecError('Parsing configspec failed: %s' % e)
1738
        except IOError, e:
1739
            raise IOError('Reading configspec failed: %s' % e)
1740
        self._set_configspec_value(configspec, self)
1741
1742
    def _set_configspec_value(self, configspec, section):
1743
        """Used to recursively set configspec values."""
1744
        if '__many__' in configspec.sections:
1745
            section.configspec['__many__'] = configspec['__many__']
1746
            if len(configspec.sections) > 1:
1747
                # FIXME: can we supply any useful information here ?
1748
                raise RepeatSectionError
1749
        for entry in configspec.scalars:
1750
            section.configspec[entry] = configspec[entry]
1751
        for entry in configspec.sections:
1752
            if entry == '__many__':
1753
                continue
1963.2.1 by Robey Pointer
remove usage of has_key()
1754
            if entry not in section:
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1755
                section[entry] = {}
1756
            self._set_configspec_value(configspec[entry], section[entry])
1757
1758
    def _handle_repeat(self, section, configspec):
1759
        """Dynamically assign configspec for repeated section."""
1760
        try:
1761
            section_keys = configspec.sections
1762
            scalar_keys = configspec.scalars
1763
        except AttributeError:
1764
            section_keys = [entry for entry in configspec 
1765
                                if isinstance(configspec[entry], dict)]
1766
            scalar_keys = [entry for entry in configspec 
1767
                                if not isinstance(configspec[entry], dict)]
1768
        if '__many__' in section_keys and len(section_keys) > 1:
1769
            # FIXME: can we supply any useful information here ?
1770
            raise RepeatSectionError
1771
        scalars = {}
1772
        sections = {}
1773
        for entry in scalar_keys:
1774
            val = configspec[entry]
1775
            scalars[entry] = val
1776
        for entry in section_keys:
1777
            val = configspec[entry]
1778
            if entry == '__many__':
1779
                scalars[entry] = val
1780
                continue
1781
            sections[entry] = val
1782
        #
1783
        section.configspec = scalars
1784
        for entry in sections:
1963.2.1 by Robey Pointer
remove usage of has_key()
1785
            if entry not in section:
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1786
                section[entry] = {}
1787
            self._handle_repeat(section[entry], sections[entry])
1788
1789
    def _write_line(self, indent_string, entry, this_entry, comment):
1790
        """Write an individual line, for the write method"""
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1791
        # NOTE: the calls to self._quote here handles non-StringType values.
1792
        return '%s%s%s%s%s' % (
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1793
            indent_string,
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1794
            self._decode_element(self._quote(entry, multiline=False)),
1795
            self._a_to_u(' = '),
1796
            self._decode_element(self._quote(this_entry)),
1797
            self._decode_element(comment))
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1798
1799
    def _write_marker(self, indent_string, depth, entry, comment):
1800
        """Write a section marker line"""
1801
        return '%s%s%s%s%s' % (
1802
            indent_string,
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1803
            self._a_to_u('[' * depth),
1804
            self._quote(self._decode_element(entry), multiline=False),
1805
            self._a_to_u(']' * depth),
1806
            self._decode_element(comment))
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1807
1808
    def _handle_comment(self, comment):
1809
        """
1810
        Deal with a comment.
1811
        
1812
        >>> filename = a.filename
1813
        >>> a.filename = None
1814
        >>> values = a.write()
1815
        >>> index = 0
1816
        >>> while index < 23:
1817
        ...     index += 1
1818
        ...     line = values[index-1]
1819
        ...     assert line.endswith('# comment ' + str(index))
1820
        >>> a.filename = filename
1821
        
1822
        >>> start_comment = ['# Initial Comment', '', '#']
1823
        >>> end_comment = ['', '#', '# Final Comment']
1824
        >>> newconfig = start_comment + testconfig1.split('\\n') + end_comment
1825
        >>> nc = ConfigObj(newconfig)
1826
        >>> nc.initial_comment
1827
        ['# Initial Comment', '', '#']
1828
        >>> nc.final_comment
1829
        ['', '#', '# Final Comment']
1830
        >>> nc.initial_comment == start_comment
1831
        1
1832
        >>> nc.final_comment == end_comment
1833
        1
1834
        """
1835
        if not comment:
1836
            return ''
1837
        if self.indent_type == '\t':
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1838
            start = self._a_to_u('\t')
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1839
        else:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1840
            start = self._a_to_u(' ' * NUM_INDENT_SPACES)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1841
        if not comment.startswith('#'):
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1842
            start += _a_to_u('# ')
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1843
        return (start + comment)
1844
1845
    def _compute_indent_string(self, depth):
1846
        """
1847
        Compute the indent string, according to current indent_type and depth
1848
        """
1849
        if self.indent_type == '':
1850
            # no indentation at all
1851
            return ''
1852
        if self.indent_type == '\t':
1853
            return '\t' * depth
1854
        if self.indent_type == ' ':
1855
            return ' ' * NUM_INDENT_SPACES * depth
1856
        raise SyntaxError
1857
1858
    # Public methods
1859
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1860
    def write(self, outfile=None, section=None):
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1861
        """
1862
        Write the current ConfigObj as a file
1863
        
1864
        tekNico: FIXME: use StringIO instead of real files
1865
        
1866
        >>> filename = a.filename
1867
        >>> a.filename = 'test.ini'
1868
        >>> a.write()
1869
        >>> a.filename = filename
1870
        >>> a == ConfigObj('test.ini', raise_errors=True)
1871
        1
1872
        >>> os.remove('test.ini')
1873
        >>> b.filename = 'test.ini'
1874
        >>> b.write()
1875
        >>> b == ConfigObj('test.ini', raise_errors=True)
1876
        1
1877
        >>> os.remove('test.ini')
1878
        >>> i.filename = 'test.ini'
1879
        >>> i.write()
1880
        >>> i == ConfigObj('test.ini', raise_errors=True)
1881
        1
1882
        >>> os.remove('test.ini')
1883
        >>> a = ConfigObj()
1884
        >>> a['DEFAULT'] = {'a' : 'fish'}
1885
        >>> a['a'] = '%(a)s'
1886
        >>> a.write()
1887
        ['a = %(a)s', '[DEFAULT]', 'a = fish']
1888
        """
1889
        if self.indent_type is None:
1890
            # this can be true if initialised from a dictionary
1891
            self.indent_type = DEFAULT_INDENT_TYPE
1892
        #
1893
        out = []
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1894
        cs = self._a_to_u('#')
1895
        csp = self._a_to_u('# ')
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1896
        if section is None:
1897
            int_val = self.interpolation
1898
            self.interpolation = False
1899
            section = self
1900
            for line in self.initial_comment:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1901
                line = self._decode_element(line)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1902
                stripped_line = line.strip()
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1903
                if stripped_line and not stripped_line.startswith(cs):
1904
                    line = csp + line
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1905
                out.append(line)
1906
        #
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1907
        indent_string = self._a_to_u(
1908
            self._compute_indent_string(section.depth))
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1909
        for entry in (section.scalars + section.sections):
1910
            if entry in section.defaults:
1911
                # don't write out default values
1912
                continue
1913
            for comment_line in section.comments[entry]:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1914
                comment_line = self._decode_element(comment_line.lstrip())
1915
                if comment_line and not comment_line.startswith(cs):
1916
                    comment_line = csp + comment_line
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1917
                out.append(indent_string + comment_line)
1918
            this_entry = section[entry]
1919
            comment = self._handle_comment(section.inline_comments[entry])
1920
            #
1921
            if isinstance(this_entry, dict):
1922
                # a section
1923
                out.append(self._write_marker(
1924
                    indent_string,
1925
                    this_entry.depth,
1926
                    entry,
1927
                    comment))
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1928
                out.extend(self.write(section=this_entry))
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1929
            else:
1930
                out.append(self._write_line(
1931
                    indent_string,
1932
                    entry,
1933
                    this_entry,
1934
                    comment))
1935
        #
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1936
        if section is self:
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1937
            for line in self.final_comment:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1938
                line = self._decode_element(line)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1939
                stripped_line = line.strip()
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1940
                if stripped_line and not stripped_line.startswith(cs):
1941
                    line = csp + line
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1942
                out.append(line)
1943
            self.interpolation = int_val
1944
        #
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1945
        if section is not self:
1946
            return out
1947
        #
1948
        if (self.filename is None) and (outfile is None):
1949
            # output a list of lines
1950
            # might need to encode
1951
            # NOTE: This will *screw* UTF16, each line will start with the BOM
1952
            if self.encoding:
1953
                out = [l.encode(self.encoding) for l in out]
1954
            if (self.BOM and ((self.encoding is None) or
1955
                (BOM_LIST.get(self.encoding.lower()) == 'utf_8'))):
1956
                # Add the UTF8 BOM
1957
                if not out:
1958
                    out.append('')
1959
                out[0] = BOM_UTF8 + out[0]
1960
            return out
1961
        #
1962
        # Turn the list to a string, joined with correct newlines
1963
        output = (self._a_to_u(self.newlines or os.linesep)
1964
            ).join(out)
1965
        if self.encoding:
1966
            output = output.encode(self.encoding)
1967
        if (self.BOM and ((self.encoding is None) or
1968
            (BOM_LIST.get(self.encoding.lower()) == 'utf_8'))):
1969
            # Add the UTF8 BOM
1970
            output = BOM_UTF8 + output
1971
        if outfile is not None:
1972
            outfile.write(output)
1973
        else:
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1974
            h = open(self.filename, 'w')
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1975
            h.write(output)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1976
            h.close()
1977
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
1978
    def validate(self, validator, preserve_errors=False, section=None):
1185.12.49 by Aaron Bentley
Switched to ConfigObj
1979
        """
1980
        Test the ConfigObj against a configspec.
1981
        
1982
        It uses the ``validator`` object from *validate.py*.
1983
        
1984
        To run ``validate`` on the current ConfigObj, call: ::
1985
        
1986
            test = config.validate(validator)
1987
        
1988
        (Normally having previously passed in the configspec when the ConfigObj
1989
        was created - you can dynamically assign a dictionary of checks to the
1990
        ``configspec`` attribute of a section though).
1991
        
1992
        It returns ``True`` if everything passes, or a dictionary of
1993
        pass/fails (True/False). If every member of a subsection passes, it
1994
        will just have the value ``True``. (It also returns ``False`` if all
1995
        members fail).
1996
        
1997
        In addition, it converts the values from strings to their native
1998
        types if their checks pass (and ``stringify`` is set).
1999
        
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2000
        If ``preserve_errors`` is ``True`` (``False`` is default) then instead
2001
        of a marking a fail with a ``False``, it will preserve the actual
2002
        exception object. This can contain info about the reason for failure.
2003
        For example the ``VdtValueTooSmallError`` indeicates that the value
2004
        supplied was too small. If a value (or section) is missing it will
2005
        still be marked as ``False``.
2006
        
2007
        You must have the validate module to use ``preserve_errors=True``.
2008
        
2009
        You can then use the ``flatten_errors`` function to turn your nested
2010
        results dictionary into a flattened list of failures - useful for
2011
        displaying meaningful error messages.
2012
        
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2013
        >>> try:
2014
        ...     from validate import Validator
2015
        ... except ImportError:
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
2016
        ...     sys.stderr.write('Cannot import the Validator object, skipping the related tests\n')
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2017
        ... else:
2018
        ...     config = '''
2019
        ...     test1=40
2020
        ...     test2=hello
2021
        ...     test3=3
2022
        ...     test4=5.0
2023
        ...     [section]
2024
        ...         test1=40
2025
        ...         test2=hello
2026
        ...         test3=3
2027
        ...         test4=5.0
2028
        ...         [[sub section]]
2029
        ...             test1=40
2030
        ...             test2=hello
2031
        ...             test3=3
2032
        ...             test4=5.0
2033
        ... '''.split('\\n')
2034
        ...     configspec = '''
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2035
        ...     test1= integer(30,50)
2036
        ...     test2= string
2037
        ...     test3=integer
2038
        ...     test4=float(6.0)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2039
        ...     [section ]
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2040
        ...         test1=integer(30,50)
2041
        ...         test2=string
2042
        ...         test3=integer
2043
        ...         test4=float(6.0)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2044
        ...         [[sub section]]
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2045
        ...             test1=integer(30,50)
2046
        ...             test2=string
2047
        ...             test3=integer
2048
        ...             test4=float(6.0)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2049
        ...     '''.split('\\n')
2050
        ...     val = Validator()
2051
        ...     c1 = ConfigObj(config, configspec=configspec)
2052
        ...     test = c1.validate(val)
2053
        ...     test == {
2054
        ...         'test1': True,
2055
        ...         'test2': True,
2056
        ...         'test3': True,
2057
        ...         'test4': False,
2058
        ...         'section': {
2059
        ...             'test1': True,
2060
        ...             'test2': True,
2061
        ...             'test3': True,
2062
        ...             'test4': False,
2063
        ...             'sub section': {
2064
        ...                 'test1': True,
2065
        ...                 'test2': True,
2066
        ...                 'test3': True,
2067
        ...                 'test4': False,
2068
        ...             },
2069
        ...         },
2070
        ...     }
2071
        1
2072
        >>> val.check(c1.configspec['test4'], c1['test4'])
2073
        Traceback (most recent call last):
2074
        VdtValueTooSmallError: the value "5.0" is too small.
2075
        
2076
        >>> val_test_config = '''
2077
        ...     key = 0
2078
        ...     key2 = 1.1
2079
        ...     [section]
2080
        ...     key = some text
2081
        ...     key2 = 1.1, 3.0, 17, 6.8
2082
        ...         [[sub-section]]
2083
        ...         key = option1
2084
        ...         key2 = True'''.split('\\n')
2085
        >>> val_test_configspec = '''
2086
        ...     key = integer
2087
        ...     key2 = float
2088
        ...     [section]
2089
        ...     key = string
2090
        ...     key2 = float_list(4)
2091
        ...        [[sub-section]]
2092
        ...        key = option(option1, option2)
2093
        ...        key2 = boolean'''.split('\\n')
2094
        >>> val_test = ConfigObj(val_test_config, configspec=val_test_configspec)
2095
        >>> val_test.validate(val)
2096
        1
2097
        >>> val_test['key'] = 'text not a digit'
2098
        >>> val_res = val_test.validate(val)
2099
        >>> val_res == {'key2': True, 'section': True, 'key': False}
2100
        1
2101
        >>> configspec = '''
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2102
        ...     test1=integer(30,50, default=40)
2103
        ...     test2=string(default="hello")
2104
        ...     test3=integer(default=3)
2105
        ...     test4=float(6.0, default=6.0)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2106
        ...     [section ]
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2107
        ...         test1=integer(30,50, default=40)
2108
        ...         test2=string(default="hello")
2109
        ...         test3=integer(default=3)
2110
        ...         test4=float(6.0, default=6.0)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2111
        ...         [[sub section]]
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2112
        ...             test1=integer(30,50, default=40)
2113
        ...             test2=string(default="hello")
2114
        ...             test3=integer(default=3)
2115
        ...             test4=float(6.0, default=6.0)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2116
        ...     '''.split('\\n')
2117
        >>> default_test = ConfigObj(['test1=30'], configspec=configspec)
2118
        >>> default_test
2119
        {'test1': '30', 'section': {'sub section': {}}}
2120
        >>> default_test.validate(val)
2121
        1
2122
        >>> default_test == {
2123
        ...     'test1': 30,
2124
        ...     'test2': 'hello',
2125
        ...     'test3': 3,
2126
        ...     'test4': 6.0,
2127
        ...     'section': {
2128
        ...         'test1': 40,
2129
        ...         'test2': 'hello',
2130
        ...         'test3': 3,
2131
        ...         'test4': 6.0,
2132
        ...         'sub section': {
2133
        ...             'test1': 40,
2134
        ...             'test3': 3,
2135
        ...             'test2': 'hello',
2136
        ...             'test4': 6.0,
2137
        ...         },
2138
        ...     },
2139
        ... }
2140
        1
2141
        
2142
        Now testing with repeated sections : BIG TEST
2143
        
2144
        >>> repeated_1 = '''
2145
        ... [dogs]
2146
        ...     [[__many__]] # spec for a dog
2147
        ...         fleas = boolean(default=True)
2148
        ...         tail = option(long, short, default=long)
2149
        ...         name = string(default=rover)
2150
        ...         [[[__many__]]]  # spec for a puppy
2151
        ...             name = string(default="son of rover")
2152
        ...             age = float(default=0.0)
2153
        ... [cats]
2154
        ...     [[__many__]] # spec for a cat
2155
        ...         fleas = boolean(default=True)
2156
        ...         tail = option(long, short, default=short)
2157
        ...         name = string(default=pussy)
2158
        ...         [[[__many__]]] # spec for a kitten
2159
        ...             name = string(default="son of pussy")
2160
        ...             age = float(default=0.0)
2161
        ...         '''.split('\\n')
2162
        >>> repeated_2 = '''
2163
        ... [dogs]
2164
        ... 
2165
        ...     # blank dogs with puppies
2166
        ...     # should be filled in by the configspec
2167
        ...     [[dog1]]
2168
        ...         [[[puppy1]]]
2169
        ...         [[[puppy2]]]
2170
        ...         [[[puppy3]]]
2171
        ...     [[dog2]]
2172
        ...         [[[puppy1]]]
2173
        ...         [[[puppy2]]]
2174
        ...         [[[puppy3]]]
2175
        ...     [[dog3]]
2176
        ...         [[[puppy1]]]
2177
        ...         [[[puppy2]]]
2178
        ...         [[[puppy3]]]
2179
        ... [cats]
2180
        ... 
2181
        ...     # blank cats with kittens
2182
        ...     # should be filled in by the configspec
2183
        ...     [[cat1]]
2184
        ...         [[[kitten1]]]
2185
        ...         [[[kitten2]]]
2186
        ...         [[[kitten3]]]
2187
        ...     [[cat2]]
2188
        ...         [[[kitten1]]]
2189
        ...         [[[kitten2]]]
2190
        ...         [[[kitten3]]]
2191
        ...     [[cat3]]
2192
        ...         [[[kitten1]]]
2193
        ...         [[[kitten2]]]
2194
        ...         [[[kitten3]]]
2195
        ... '''.split('\\n')
2196
        >>> repeated_3 = '''
2197
        ... [dogs]
2198
        ... 
2199
        ...     [[dog1]]
2200
        ...     [[dog2]]
2201
        ...     [[dog3]]
2202
        ... [cats]
2203
        ... 
2204
        ...     [[cat1]]
2205
        ...     [[cat2]]
2206
        ...     [[cat3]]
2207
        ... '''.split('\\n')
2208
        >>> repeated_4 = '''
2209
        ... [__many__]
2210
        ... 
2211
        ...     name = string(default=Michael)
2212
        ...     age = float(default=0.0)
2213
        ...     sex = option(m, f, default=m)
2214
        ... '''.split('\\n')
2215
        >>> repeated_5 = '''
2216
        ... [cats]
2217
        ... [[__many__]]
2218
        ...     fleas = boolean(default=True)
2219
        ...     tail = option(long, short, default=short)
2220
        ...     name = string(default=pussy)
2221
        ...     [[[description]]]
2222
        ...         height = float(default=3.3)
2223
        ...         weight = float(default=6)
2224
        ...         [[[[coat]]]]
2225
        ...             fur = option(black, grey, brown, "tortoise shell", default=black)
2226
        ...             condition = integer(0,10, default=5)
2227
        ... '''.split('\\n')
2228
        >>> from validate import Validator
2229
        >>> val= Validator()
2230
        >>> repeater = ConfigObj(repeated_2, configspec=repeated_1)
2231
        >>> repeater.validate(val)
2232
        1
2233
        >>> repeater == {
2234
        ...     'dogs': {
2235
        ...         'dog1': {
2236
        ...             'fleas': True,
2237
        ...             'tail': 'long',
2238
        ...             'name': 'rover',
2239
        ...             'puppy1': {'name': 'son of rover', 'age': 0.0},
2240
        ...             'puppy2': {'name': 'son of rover', 'age': 0.0},
2241
        ...             'puppy3': {'name': 'son of rover', 'age': 0.0},
2242
        ...         },
2243
        ...         'dog2': {
2244
        ...             'fleas': True,
2245
        ...             'tail': 'long',
2246
        ...             'name': 'rover',
2247
        ...             'puppy1': {'name': 'son of rover', 'age': 0.0},
2248
        ...             'puppy2': {'name': 'son of rover', 'age': 0.0},
2249
        ...             'puppy3': {'name': 'son of rover', 'age': 0.0},
2250
        ...         },
2251
        ...         'dog3': {
2252
        ...             'fleas': True,
2253
        ...             'tail': 'long',
2254
        ...             'name': 'rover',
2255
        ...             'puppy1': {'name': 'son of rover', 'age': 0.0},
2256
        ...             'puppy2': {'name': 'son of rover', 'age': 0.0},
2257
        ...             'puppy3': {'name': 'son of rover', 'age': 0.0},
2258
        ...         },
2259
        ...     },
2260
        ...     'cats': {
2261
        ...         'cat1': {
2262
        ...             'fleas': True,
2263
        ...             'tail': 'short',
2264
        ...             'name': 'pussy',
2265
        ...             'kitten1': {'name': 'son of pussy', 'age': 0.0},
2266
        ...             'kitten2': {'name': 'son of pussy', 'age': 0.0},
2267
        ...             'kitten3': {'name': 'son of pussy', 'age': 0.0},
2268
        ...         },
2269
        ...         'cat2': {
2270
        ...             'fleas': True,
2271
        ...             'tail': 'short',
2272
        ...             'name': 'pussy',
2273
        ...             'kitten1': {'name': 'son of pussy', 'age': 0.0},
2274
        ...             'kitten2': {'name': 'son of pussy', 'age': 0.0},
2275
        ...             'kitten3': {'name': 'son of pussy', 'age': 0.0},
2276
        ...         },
2277
        ...         'cat3': {
2278
        ...             'fleas': True,
2279
        ...             'tail': 'short',
2280
        ...             'name': 'pussy',
2281
        ...             'kitten1': {'name': 'son of pussy', 'age': 0.0},
2282
        ...             'kitten2': {'name': 'son of pussy', 'age': 0.0},
2283
        ...             'kitten3': {'name': 'son of pussy', 'age': 0.0},
2284
        ...         },
2285
        ...     },
2286
        ... }
2287
        1
2288
        >>> repeater = ConfigObj(repeated_3, configspec=repeated_1)
2289
        >>> repeater.validate(val)
2290
        1
2291
        >>> repeater == {
2292
        ...     'cats': {
2293
        ...         'cat1': {'fleas': True, 'tail': 'short', 'name': 'pussy'},
2294
        ...         'cat2': {'fleas': True, 'tail': 'short', 'name': 'pussy'},
2295
        ...         'cat3': {'fleas': True, 'tail': 'short', 'name': 'pussy'},
2296
        ...     },
2297
        ...     'dogs': {
2298
        ...         'dog1': {'fleas': True, 'tail': 'long', 'name': 'rover'},
2299
        ...         'dog2': {'fleas': True, 'tail': 'long', 'name': 'rover'},
2300
        ...         'dog3': {'fleas': True, 'tail': 'long', 'name': 'rover'},
2301
        ...     },
2302
        ... }
2303
        1
2304
        >>> repeater = ConfigObj(configspec=repeated_4)
2305
        >>> repeater['Michael'] = {}
2306
        >>> repeater.validate(val)
2307
        1
2308
        >>> repeater == {
2309
        ...     'Michael': {'age': 0.0, 'name': 'Michael', 'sex': 'm'},
2310
        ... }
2311
        1
2312
        >>> repeater = ConfigObj(repeated_3, configspec=repeated_5)
2313
        >>> repeater == {
2314
        ...     'dogs': {'dog1': {}, 'dog2': {}, 'dog3': {}},
2315
        ...     'cats': {'cat1': {}, 'cat2': {}, 'cat3': {}},
2316
        ... }
2317
        1
2318
        >>> repeater.validate(val)
2319
        1
2320
        >>> repeater == {
2321
        ...     'dogs': {'dog1': {}, 'dog2': {}, 'dog3': {}},
2322
        ...     'cats': {
2323
        ...         'cat1': {
2324
        ...             'fleas': True,
2325
        ...             'tail': 'short',
2326
        ...             'name': 'pussy',
2327
        ...             'description': {
2328
        ...                 'weight': 6.0,
2329
        ...                 'height': 3.2999999999999998,
2330
        ...                 'coat': {'fur': 'black', 'condition': 5},
2331
        ...             },
2332
        ...         },
2333
        ...         'cat2': {
2334
        ...             'fleas': True,
2335
        ...             'tail': 'short',
2336
        ...             'name': 'pussy',
2337
        ...             'description': {
2338
        ...                 'weight': 6.0,
2339
        ...                 'height': 3.2999999999999998,
2340
        ...                 'coat': {'fur': 'black', 'condition': 5},
2341
        ...             },
2342
        ...         },
2343
        ...         'cat3': {
2344
        ...             'fleas': True,
2345
        ...             'tail': 'short',
2346
        ...             'name': 'pussy',
2347
        ...             'description': {
2348
        ...                 'weight': 6.0,
2349
        ...                 'height': 3.2999999999999998,
2350
        ...                 'coat': {'fur': 'black', 'condition': 5},
2351
        ...             },
2352
        ...         },
2353
        ...     },
2354
        ... }
2355
        1
2356
        
2357
        Test that interpolation is preserved for validated string values.
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2358
        Also check that interpolation works in configspecs.
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2359
        >>> t = ConfigObj()
2360
        >>> t['DEFAULT'] = {}
2361
        >>> t['DEFAULT']['test'] = 'a'
2362
        >>> t['test'] = '%(test)s'
2363
        >>> t['test']
2364
        'a'
2365
        >>> v = Validator()
2366
        >>> t.configspec = {'test': 'string'}
2367
        >>> t.validate(v)
2368
        1
2369
        >>> t.interpolation = False
2370
        >>> t
2371
        {'test': '%(test)s', 'DEFAULT': {'test': 'a'}}
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2372
        >>> specs = [
2373
        ...    'interpolated string  = string(default="fuzzy-%(man)s")',
2374
        ...    '[DEFAULT]',
2375
        ...    'man = wuzzy',
2376
        ...    ]
2377
        >>> c = ConfigObj(configspec=specs)
2378
        >>> c.validate(v)
2379
        1
2380
        >>> c['interpolated string']
2381
        'fuzzy-wuzzy'
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2382
        
2383
        FIXME: Above tests will fail if we couldn't import Validator (the ones
2384
        that don't raise errors will produce different output and still fail as
2385
        tests)
2386
        """
2387
        if section is None:
2388
            if self.configspec is None:
2389
                raise ValueError, 'No configspec supplied.'
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2390
            if preserve_errors:
2391
                if VdtMissingValue is None:
2392
                    raise ImportError('Missing validate module.')
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2393
            section = self
2394
        #
2395
        spec_section = section.configspec
2396
        if '__many__' in section.configspec:
2397
            many = spec_section['__many__']
2398
            # dynamically assign the configspecs
2399
            # for the sections below
2400
            for entry in section.sections:
2401
                self._handle_repeat(section[entry], many)
2402
        #
2403
        out = {}
2404
        ret_true = True
2405
        ret_false = True
2406
        for entry in spec_section:
2407
            if entry == '__many__':
2408
                continue
2409
            if (not entry in section.scalars) or (entry in section.defaults):
2410
                # missing entries
2411
                # or entries from defaults
2412
                missing = True
2413
                val = None
2414
            else:
2415
                missing = False
2416
                val = section[entry]
2417
            try:
2418
                check = validator.check(spec_section[entry],
2419
                                        val,
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2420
                                        missing=missing
2421
                                        )
2422
            except validator.baseErrorClass, e:
2423
                if not preserve_errors or isinstance(e, VdtMissingValue):
2424
                    out[entry] = False
2425
                else:
2426
                    # preserve the error
2427
                    out[entry] = e
2428
                    ret_false = False
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2429
                ret_true = False
2430
            else:
2431
                ret_false = False
2432
                out[entry] = True
2433
                if self.stringify or missing:
2434
                    # if we are doing type conversion
2435
                    # or the value is a supplied default
2436
                    if not self.stringify:
2437
                        if isinstance(check, (list, tuple)):
2438
                            # preserve lists
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2439
                            check = [self._str(item) for item in check]
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2440
                        elif missing and check is None:
2441
                            # convert the None from a default to a ''
2442
                            check = ''
2443
                        else:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2444
                            check = self._str(check)
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2445
                    if (check != val) or missing:
2446
                        section[entry] = check
2447
                if missing and entry not in section.defaults:
2448
                    section.defaults.append(entry)
2449
        #
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2450
        # FIXME: Will this miss missing sections ?
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2451
        for entry in section.sections:
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2452
            if section is self and entry == 'DEFAULT':
2453
                continue
2454
            check = self.validate(validator, preserve_errors=preserve_errors,
2455
                section=section[entry])
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2456
            out[entry] = check
2457
            if check == False:
2458
                ret_true = False
2459
            elif check == True:
2460
                ret_false = False
2461
            else:
2462
                ret_true = False
2463
                ret_false = False
2464
        #
2465
        if ret_true:
2466
            return True
2467
        elif ret_false:
2468
            return False
2469
        else:
2470
            return out
2471
2472
class SimpleVal(object):
2473
    """
2474
    A simple validator.
2475
    Can be used to check that all members expected are present.
2476
    
2477
    To use it, provide a configspec with all your members in (the value given
2478
    will be ignored). Pass an instance of ``SimpleVal`` to the ``validate``
2479
    method of your ``ConfigObj``. ``validate`` will return ``True`` if all
2480
    members are present, or a dictionary with True/False meaning
2481
    present/missing. (Whole missing sections will be replaced with ``False``)
2482
    
2483
    >>> val = SimpleVal()
2484
    >>> config = '''
2485
    ... test1=40
2486
    ... test2=hello
2487
    ... test3=3
2488
    ... test4=5.0
2489
    ... [section]
2490
    ... test1=40
2491
    ... test2=hello
2492
    ... test3=3
2493
    ... test4=5.0
2494
    ...     [[sub section]]
2495
    ...     test1=40
2496
    ...     test2=hello
2497
    ...     test3=3
2498
    ...     test4=5.0
2499
    ... '''.split('\\n')
2500
    >>> configspec = '''
2501
    ... test1=''
2502
    ... test2=''
2503
    ... test3=''
2504
    ... test4=''
2505
    ... [section]
2506
    ... test1=''
2507
    ... test2=''
2508
    ... test3=''
2509
    ... test4=''
2510
    ...     [[sub section]]
2511
    ...     test1=''
2512
    ...     test2=''
2513
    ...     test3=''
2514
    ...     test4=''
2515
    ... '''.split('\\n')
2516
    >>> o = ConfigObj(config, configspec=configspec)
2517
    >>> o.validate(val)
2518
    1
2519
    >>> o = ConfigObj(configspec=configspec)
2520
    >>> o.validate(val)
2521
    0
2522
    """
2523
    
2524
    def __init__(self):
2525
        self.baseErrorClass = ConfigObjError
2526
    
2527
    def check(self, check, member, missing=False):
2528
        """A dummy check method, always returns the value unchanged."""
2529
        if missing:
2530
            raise self.baseErrorClass
2531
        return member
2532
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2533
# Check / processing functions for options
2534
def flatten_errors(cfg, res, levels=None, results=None):
2535
    """
2536
    An example function that will turn a nested dictionary of results
2537
    (as returned by ``ConfigObj.validate``) into a flat list.
2538
    
2539
    ``cfg`` is the ConfigObj instance being checked, ``res`` is the results
2540
    dictionary returned by ``validate``.
2541
    
2542
    (This is a recursive function, so you shouldn't use the ``levels`` or
2543
    ``results`` arguments - they are used by the function.
2544
    
2545
    Returns a list of keys that failed. Each member of the list is a tuple :
2546
    ::
2547
    
2548
        ([list of sections...], key, result)
2549
    
2550
    If ``validate`` was called with ``preserve_errors=False`` (the default)
2551
    then ``result`` will always be ``False``.
2552
2553
    *list of sections* is a flattened list of sections that the key was found
2554
    in.
2555
    
2556
    If the section was missing then key will be ``None``.
2557
    
2558
    If the value (or section) was missing then ``result`` will be ``False``.
2559
    
2560
    If ``validate`` was called with ``preserve_errors=True`` and a value
2561
    was present, but failed the check, then ``result`` will be the exception
2562
    object returned. You can use this as a string that describes the failure.
2563
    
2564
    For example *The value "3" is of the wrong type*.
2565
    
2566
    # FIXME: is the ordering of the output arbitrary ?
2567
    >>> import validate
2568
    >>> vtor = validate.Validator()
2569
    >>> my_ini = '''
2570
    ...     option1 = True
2571
    ...     [section1]
2572
    ...     option1 = True
2573
    ...     [section2]
2574
    ...     another_option = Probably
2575
    ...     [section3]
2576
    ...     another_option = True
2577
    ...     [[section3b]]
2578
    ...     value = 3
2579
    ...     value2 = a
2580
    ...     value3 = 11
2581
    ...     '''
2582
    >>> my_cfg = '''
2583
    ...     option1 = boolean()
2584
    ...     option2 = boolean()
2585
    ...     option3 = boolean(default=Bad_value)
2586
    ...     [section1]
2587
    ...     option1 = boolean()
2588
    ...     option2 = boolean()
2589
    ...     option3 = boolean(default=Bad_value)
2590
    ...     [section2]
2591
    ...     another_option = boolean()
2592
    ...     [section3]
2593
    ...     another_option = boolean()
2594
    ...     [[section3b]]
2595
    ...     value = integer
2596
    ...     value2 = integer
2597
    ...     value3 = integer(0, 10)
2598
    ...         [[[section3b-sub]]]
2599
    ...         value = string
2600
    ...     [section4]
2601
    ...     another_option = boolean()
2602
    ...     '''
2603
    >>> cs = my_cfg.split('\\n')
2604
    >>> ini = my_ini.split('\\n')
2605
    >>> cfg = ConfigObj(ini, configspec=cs)
2606
    >>> res = cfg.validate(vtor, preserve_errors=True)
2607
    >>> errors = []
2608
    >>> for entry in flatten_errors(cfg, res):
2609
    ...     section_list, key, error = entry
2610
    ...     section_list.insert(0, '[root]')
2611
    ...     if key is not None:
2612
    ...        section_list.append(key)
2613
    ...     else:
2614
    ...         section_list.append('[missing]')
2615
    ...     section_string = ', '.join(section_list)
2616
    ...     errors.append((section_string, ' = ', error))
2617
    >>> errors.sort()
2618
    >>> for entry in errors:
2619
    ...     print entry[0], entry[1], (entry[2] or 0)
2620
    [root], option2  =  0
2621
    [root], option3  =  the value "Bad_value" is of the wrong type.
2622
    [root], section1, option2  =  0
2623
    [root], section1, option3  =  the value "Bad_value" is of the wrong type.
2624
    [root], section2, another_option  =  the value "Probably" is of the wrong type.
2625
    [root], section3, section3b, section3b-sub, [missing]  =  0
2626
    [root], section3, section3b, value2  =  the value "a" is of the wrong type.
2627
    [root], section3, section3b, value3  =  the value "11" is too big.
2628
    [root], section4, [missing]  =  0
2629
    """
2630
    if levels is None:
2631
        # first time called
2632
        levels = []
2633
        results = []
2634
    if res is True:
2635
        return results
2636
    if res is False:
2637
        results.append((levels[:], None, False))
2638
        if levels:
2639
            levels.pop()
2640
        return results
2641
    for (key, val) in res.items():
2642
        if val == True:
2643
            continue
2644
        if isinstance(cfg.get(key), dict):
2645
            # Go down one level
2646
            levels.append(key)
2647
            flatten_errors(cfg[key], val, levels, results)
2648
            continue
2649
        results.append((levels[:], key, val))
2650
    #
2651
    # Go up one level
2652
    if levels:
2653
        levels.pop()
2654
    #
2655
    return results
2656
2657
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2658
# FIXME: test error code for badly built multiline values
2659
# FIXME: test handling of StringIO
2660
# FIXME: test interpolation with writing
2661
2662
def _doctest():
2663
    """
2664
    Dummy function to hold some of the doctests.
2665
    
2666
    >>> a.depth
2667
    0
2668
    >>> a == {
2669
    ...     'key2': 'val',
2670
    ...     'key1': 'val',
2671
    ...     'lev1c': {
2672
    ...         'lev2c': {
2673
    ...             'lev3c': {
2674
    ...                 'key1': 'val',
2675
    ...             },
2676
    ...         },
2677
    ...     },
2678
    ...     'lev1b': {
2679
    ...         'key2': 'val',
2680
    ...         'key1': 'val',
2681
    ...         'lev2ba': {
2682
    ...             'key1': 'val',
2683
    ...         },
2684
    ...         'lev2bb': {
2685
    ...             'key1': 'val',
2686
    ...         },
2687
    ...     },
2688
    ...     'lev1a': {
2689
    ...         'key2': 'val',
2690
    ...         'key1': 'val',
2691
    ...     },
2692
    ... }
2693
    1
2694
    >>> b.depth
2695
    0
2696
    >>> b == {
2697
    ...     'key3': 'val3',
2698
    ...     'key2': 'val2',
2699
    ...     'key1': 'val1',
2700
    ...     'section 1': {
2701
    ...         'keys11': 'val1',
2702
    ...         'keys13': 'val3',
2703
    ...         'keys12': 'val2',
2704
    ...     },
2705
    ...     'section 2': {
2706
    ...         'section 2 sub 1': {
2707
    ...             'fish': '3',
2708
    ...     },
2709
    ...     'keys21': 'val1',
2710
    ...     'keys22': 'val2',
2711
    ...     'keys23': 'val3',
2712
    ...     },
2713
    ... }
2714
    1
2715
    >>> t = '''
2716
    ... 'a' = b # !"$%^&*(),::;'@~#= 33
2717
    ... "b" = b #= 6, 33
2718
    ... ''' .split('\\n')
2719
    >>> t2 = ConfigObj(t)
2720
    >>> assert t2 == {'a': 'b', 'b': 'b'}
2721
    >>> t2.inline_comments['b'] = ''
2722
    >>> del t2['a']
2723
    >>> assert t2.write() == ['','b = b', '']
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2724
    
2725
    # Test ``list_values=False`` stuff
2726
    >>> c = '''
2727
    ...     key1 = no quotes
2728
    ...     key2 = 'single quotes'
2729
    ...     key3 = "double quotes"
2730
    ...     key4 = "list", 'with', several, "quotes"
2731
    ...     '''
2732
    >>> cfg = ConfigObj(c.splitlines(), list_values=False)
2733
    >>> cfg == {'key1': 'no quotes', 'key2': "'single quotes'", 
2734
    ... 'key3': '"double quotes"', 
2735
    ... 'key4': '"list", \\'with\\', several, "quotes"'
2736
    ... }
2737
    1
2738
    >>> cfg = ConfigObj(list_values=False)
2739
    >>> cfg['key1'] = 'Multiline\\nValue'
2740
    >>> cfg['key2'] = '''"Value" with 'quotes' !'''
2741
    >>> cfg.write()
2742
    ["key1 = '''Multiline\\nValue'''", 'key2 = "Value" with \\'quotes\\' !']
2743
    >>> cfg.list_values = True
2744
    >>> cfg.write() == ["key1 = '''Multiline\\nValue'''",
2745
    ... 'key2 = \\'\\'\\'"Value" with \\'quotes\\' !\\'\\'\\'']
2746
    1
2747
    
2748
    Test flatten_errors:
2749
    
2750
    >>> from validate import Validator, VdtValueTooSmallError
2751
    >>> config = '''
2752
    ...     test1=40
2753
    ...     test2=hello
2754
    ...     test3=3
2755
    ...     test4=5.0
2756
    ...     [section]
2757
    ...         test1=40
2758
    ...         test2=hello
2759
    ...         test3=3
2760
    ...         test4=5.0
2761
    ...         [[sub section]]
2762
    ...             test1=40
2763
    ...             test2=hello
2764
    ...             test3=3
2765
    ...             test4=5.0
2766
    ... '''.split('\\n')
2767
    >>> configspec = '''
2768
    ...     test1= integer(30,50)
2769
    ...     test2= string
2770
    ...     test3=integer
2771
    ...     test4=float(6.0)
2772
    ...     [section ]
2773
    ...         test1=integer(30,50)
2774
    ...         test2=string
2775
    ...         test3=integer
2776
    ...         test4=float(6.0)
2777
    ...         [[sub section]]
2778
    ...             test1=integer(30,50)
2779
    ...             test2=string
2780
    ...             test3=integer
2781
    ...             test4=float(6.0)
2782
    ...     '''.split('\\n')
2783
    >>> val = Validator()
2784
    >>> c1 = ConfigObj(config, configspec=configspec)
2785
    >>> res = c1.validate(val)
2786
    >>> flatten_errors(c1, res) == [([], 'test4', False), (['section', 
2787
    ...     'sub section'], 'test4', False), (['section'], 'test4', False)]
2788
    True
2789
    >>> res = c1.validate(val, preserve_errors=True)
2790
    >>> check = flatten_errors(c1, res)
2791
    >>> check[0][:2]
2792
    ([], 'test4')
2793
    >>> check[1][:2]
2794
    (['section', 'sub section'], 'test4')
2795
    >>> check[2][:2]
2796
    (['section'], 'test4')
2797
    >>> for entry in check:
2798
    ...     isinstance(entry[2], VdtValueTooSmallError)
2799
    ...     print str(entry[2])
2800
    True
2801
    the value "5.0" is too small.
2802
    True
2803
    the value "5.0" is too small.
2804
    True
2805
    the value "5.0" is too small.
2806
    
2807
    Test unicode handling, BOM, write witha file like object and line endings :
2808
    >>> u_base = '''
2809
    ... # initial comment
2810
    ...     # inital comment 2
2811
    ... 
2812
    ... test1 = some value
2813
    ... # comment
2814
    ... test2 = another value    # inline comment
2815
    ... # section comment
2816
    ... [section]    # inline comment
2817
    ...     test = test    # another inline comment
2818
    ...     test2 = test2
2819
    ... 
2820
    ... # final comment
2821
    ... # final comment2
2822
    ... '''
2823
    >>> u = u_base.encode('utf_8').splitlines(True)
2824
    >>> u[0] = BOM_UTF8 + u[0]
2825
    >>> uc = ConfigObj(u)
2826
    >>> uc.encoding = None
2827
    >>> uc.BOM == True
2828
    1
2829
    >>> uc == {'test1': 'some value', 'test2': 'another value',
2830
    ... 'section': {'test': 'test', 'test2': 'test2'}}
2831
    1
2832
    >>> uc = ConfigObj(u, encoding='utf_8', default_encoding='latin-1')
2833
    >>> uc.BOM
2834
    1
2835
    >>> isinstance(uc['test1'], unicode)
2836
    1
2837
    >>> uc.encoding
2838
    'utf_8'
2839
    >>> uc.newlines
2840
    '\\n'
2841
    >>> uc['latin1'] = "This costs lot's of "
2842
    >>> a_list = uc.write()
2843
    >>> len(a_list)
2844
    15
2845
    >>> isinstance(a_list[0], str)
2846
    1
2847
    >>> a_list[0].startswith(BOM_UTF8)
2848
    1
2849
    >>> u = u_base.replace('\\n', '\\r\\n').encode('utf_8').splitlines(True)
2850
    >>> uc = ConfigObj(u)
2851
    >>> uc.newlines
2852
    '\\r\\n'
2853
    >>> uc.newlines = '\\r'
2854
    >>> from cStringIO import StringIO
2855
    >>> file_like = StringIO()
2856
    >>> uc.write(file_like)
2857
    >>> file_like.seek(0)
2858
    >>> uc2 = ConfigObj(file_like)
2859
    >>> uc2 == uc
2860
    1
1963.2.6 by Robey Pointer
pychecker is on crack; go back to using 'is None'.
2861
    >>> uc2.filename is None
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2862
    1
2863
    >>> uc2.newlines == '\\r'
2864
    1
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2865
    """
2866
2867
if __name__ == '__main__':
2868
    # run the code tests in doctest format
2869
    #
2870
    testconfig1 = """\
2871
    key1= val    # comment 1
2872
    key2= val    # comment 2
2873
    # comment 3
2874
    [lev1a]     # comment 4
2875
    key1= val    # comment 5
2876
    key2= val    # comment 6
2877
    # comment 7
2878
    [lev1b]    # comment 8
2879
    key1= val    # comment 9
2880
    key2= val    # comment 10
2881
    # comment 11
2882
        [[lev2ba]]    # comment 12
2883
        key1= val    # comment 13
2884
        # comment 14
2885
        [[lev2bb]]    # comment 15
2886
        key1= val    # comment 16
2887
    # comment 17
2888
    [lev1c]    # comment 18
2889
    # comment 19
2890
        [[lev2c]]    # comment 20
2891
        # comment 21
2892
            [[[lev3c]]]    # comment 22
2893
            key1 = val    # comment 23"""
2894
    #
2895
    testconfig2 = """\
2896
                        key1 = 'val1'
2897
                        key2 =   "val2"
2898
                        key3 = val3
2899
                        ["section 1"] # comment
2900
                        keys11 = val1
2901
                        keys12 = val2
2902
                        keys13 = val3
2903
                        [section 2]
2904
                        keys21 = val1
2905
                        keys22 = val2
2906
                        keys23 = val3
2907
                        
2908
                            [['section 2 sub 1']]
2909
                            fish = 3
2910
    """
2911
    #
2912
    testconfig6 = '''
2913
    name1 = """ a single line value """ # comment
2914
    name2 = \''' another single line value \''' # comment
2915
    name3 = """ a single line value """
2916
    name4 = \''' another single line value \'''
2917
        [ "multi section" ]
2918
        name1 = """
2919
        Well, this is a
2920
        multiline value
2921
        """
2922
        name2 = \'''
2923
        Well, this is a
2924
        multiline value
2925
        \'''
2926
        name3 = """
2927
        Well, this is a
2928
        multiline value
2929
        """     # a comment
2930
        name4 = \'''
2931
        Well, this is a
2932
        multiline value
2933
        \'''  # I guess this is a comment too
2934
    '''
2935
    #
2936
    import doctest
2937
    m = sys.modules.get('__main__')
2938
    globs = m.__dict__.copy()
2939
    a = ConfigObj(testconfig1.split('\n'), raise_errors=True)
2940
    b = ConfigObj(testconfig2.split('\n'), raise_errors=True)
2941
    i = ConfigObj(testconfig6.split('\n'), raise_errors=True)
2942
    globs.update({
2943
        'INTP_VER': INTP_VER,
2944
        'a': a,
2945
        'b': b,
2946
        'i': i,
2947
    })
2948
    doctest.testmod(m, globs=globs)
2949
2950
"""
2951
    BUGS
2952
    ====
2953
    
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2954
    None known.
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2955
    
2956
    TODO
2957
    ====
2958
    
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2959
    Better support for configuration from multiple files, including tracking
2960
    *where* the original file came from and writing changes to the correct
2961
    file.
2962
    
2963
    
2964
    Make ``newline`` an option (as well as an attribute) ?
2965
    
2966
    ``UTF16`` encoded files, when returned as a list of lines, will have the
2967
    BOM at the start of every line. Should this be removed from all but the
2968
    first line ?
2969
    
2970
    Option to set warning type for unicode decode ? (Defaults to strict).
2971
    
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2972
    A method to optionally remove uniform indentation from multiline values.
2973
    (do as an example of using ``walk`` - along with string-escape)
2974
    
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
2975
    Should the results dictionary from validate be an ordered dictionary if
2976
    `odict <http://www.voidspace.org.uk/python/odict.html>`_ is available ?
2977
    
2978
    Implement a better ``__repr__`` ? (``ConfigObj({})``)
2979
    
2980
    Implement some of the sequence methods (which include slicing) from the
2981
    newer ``odict`` ?
2982
    
1185.12.49 by Aaron Bentley
Switched to ConfigObj
2983
    INCOMPATIBLE CHANGES
2984
    ====================
2985
    
2986
    (I have removed a lot of needless complications - this list is probably not
2987
    conclusive, many option/attribute/method names have changed)
2988
    
2989
    Case sensitive
2990
    
2991
    The only valid divider is '='
2992
    
2993
    We've removed line continuations with '\'
2994
    
2995
    No recursive lists in values
2996
    
2997
    No empty section
2998
    
2999
    No distinction between flatfiles and non flatfiles
3000
    
3001
    Change in list syntax - use commas to indicate list, not parentheses
3002
    (square brackets and parentheses are no longer recognised as lists)
3003
    
3004
    ';' is no longer valid for comments and no multiline comments
3005
    
3006
    No attribute access
3007
    
3008
    We don't allow empty values - have to use '' or ""
3009
    
3010
    In ConfigObj 3 - setting a non-flatfile member to ``None`` would
3011
    initialise it as an empty section.
3012
    
3013
    The escape entities '&mjf-lf;' and '&mjf-quot;' have gone
3014
    replaced by triple quote, multiple line values.
3015
    
3016
    The ``newline``, ``force_return``, and ``default`` options have gone
3017
    
3018
    The ``encoding`` and ``backup_encoding`` methods have gone - replaced
3019
    with the ``encode`` and ``decode`` methods.
3020
    
3021
    ``fileerror`` and ``createempty`` options have become ``file_error`` and
3022
    ``create_empty``
3023
    
3024
    Partial configspecs (for specifying the order members should be written
3025
    out and which should be present) have gone. The configspec is no longer
3026
    used to specify order for the ``write`` method.
3027
    
3028
    Exceeding the maximum depth of recursion in string interpolation now
3029
    raises an error ``InterpolationDepthError``.
3030
    
3031
    Specifying a value for interpolation which doesn't exist now raises an
3032
    error ``MissingInterpolationOption`` (instead of merely being ignored).
3033
    
3034
    The ``writein`` method has been removed.
3035
    
3036
    The comments attribute is now a list (``inline_comments`` equates to the
3037
    old comments attribute)
3038
    
3039
    ISSUES
3040
    ======
3041
    
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
3042
    ``validate`` doesn't report *extra* values or sections.
3043
    
1185.12.49 by Aaron Bentley
Switched to ConfigObj
3044
    You can't have a keyword with the same name as a section (in the same
3045
    section). They are both dictionary keys - so they would overlap.
3046
    
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
3047
    ConfigObj doesn't quote and unquote values if ``list_values=False``.
3048
    This means that leading or trailing whitespace in values will be lost when
3049
    writing. (Unless you manually quote).
3050
    
1185.12.49 by Aaron Bentley
Switched to ConfigObj
3051
    Interpolation checks first the 'DEFAULT' subsection of the current
3052
    section, next it checks the 'DEFAULT' section of the parent section,
3053
    last it checks the 'DEFAULT' section of the main section.
3054
    
3055
    Logically a 'DEFAULT' section should apply to all subsections of the *same
3056
    parent* - this means that checking the 'DEFAULT' subsection in the
3057
    *current section* is not necessarily logical ?
3058
    
3059
    In order to simplify unicode support (which is possibly of limited value
3060
    in a config file) I have removed automatic support and added the
3061
    ``encode`` and ``decode methods, which can be used to transform keys and
3062
    entries. Because the regex looks for specific values on inital parsing
3063
    (i.e. the quotes and the equals signs) it can only read ascii compatible
3064
    encodings. For unicode use ``UTF8``, which is ASCII compatible.
3065
    
3066
    Does it matter that we don't support the ':' divider, which is supported
3067
    by ``ConfigParser`` ?
3068
    
3069
    The regular expression correctly removes the value -
3070
    ``"'hello', 'goodbye'"`` and then unquote just removes the front and
3071
    back quotes (called from ``_handle_value``). What should we do ??
3072
    (*ought* to raise exception because it's an invalid value if lists are
3073
    off *sigh*. This is not what you want if you want to do your own list
3074
    processing - would be *better* in this case not to unquote.)
3075
    
3076
    String interpolation and validation don't play well together. When
3077
    validation changes type it sets the value. This will correctly fetch the
3078
    value using interpolation - but then overwrite the interpolation reference.
3079
    If the value is unchanged by validation (it's a string) - but other types
3080
    will be.
3081
    
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
3082
    
1185.12.49 by Aaron Bentley
Switched to ConfigObj
3083
    List Value Syntax
3084
    =================
3085
    
3086
    List values allow you to specify multiple values for a keyword. This
3087
    maps to a list as the resulting Python object when parsed.
3088
    
3089
    The syntax for lists is easy. A list is a comma separated set of values.
3090
    If these values contain quotes, the hash mark, or commas, then the values
3091
    can be surrounded by quotes. e.g. : ::
3092
    
3093
        keyword = value1, 'value 2', "value 3"
3094
    
3095
    If a value needs to be a list, but only has one member, then you indicate
3096
    this with a trailing comma. e.g. : ::
3097
    
3098
        keyword = "single value",
3099
    
3100
    If a value needs to be a list, but it has no members, then you indicate
3101
    this with a single comma. e.g. : ::
3102
    
3103
        keyword = ,     # an empty list
3104
    
3105
    Using triple quotes it will be possible for single values to contain
3106
    newlines and *both* single quotes and double quotes. Triple quotes aren't
3107
    allowed in list values. This means that the members of list values can't
3108
    contain carriage returns (or line feeds :-) or both quote values.
3109
      
3110
    CHANGELOG
3111
    =========
3112
    
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
3113
    2006/02/04
3114
    ----------
3115
    
3116
    Removed ``BOM_UTF8`` from ``__all__``.
3117
    
3118
    The ``BOM`` attribute has become a boolean. (Defaults to ``False``.) It is
3119
    *only* ``True`` for the ``UTF16`` encoding.
3120
    
3121
    File like objects no longer need a ``seek`` attribute.
3122
    
3123
    ConfigObj no longer keeps a reference to file like objects. Instead the
3124
    ``write`` method takes a file like object as an optional argument. (Which
3125
    will be used in preference of the ``filename`` attribute if htat exists as
3126
    well.)
3127
    
3128
    Full unicode support added. New options/attributes ``encoding``,
3129
    ``default_encoding``.
3130
    
3131
    utf16 files decoded to unicode.
3132
    
3133
    If ``BOM`` is ``True``, but no encoding specified, then the utf8 BOM is
3134
    written out at the start of the file. (It will normally only be ``True`` if
3135
    the utf8 BOM was found when the file was read.)
3136
    
3137
    File paths are *not* converted to absolute paths, relative paths will
3138
    remain relative as the ``filename`` attribute.
3139
    
3140
    Fixed bug where ``final_comment`` wasn't returned if ``write`` is returning
3141
    a list of lines.
3142
    
3143
    2006/01/31
3144
    ----------
3145
    
3146
    Added ``True``, ``False``, and ``enumerate`` if they are not defined.
3147
    (``True`` and ``False`` are needed for *early* versions of Python 2.2,
3148
    ``enumerate`` is needed for all versions ofPython 2.2)
3149
    
3150
    Deprecated ``istrue``, replaced it with ``as_bool``.
3151
    
3152
    Added ``as_int`` and ``as_float``.
3153
    
3154
    utf8 and utf16 BOM handled in an endian agnostic way.
3155
    
3156
    2005/12/14
3157
    ----------
3158
    
3159
    Validation no longer done on the 'DEFAULT' section (only in the root
3160
    level). This allows interpolation in configspecs.
3161
    
3162
    Change in validation syntax implemented in validate 0.2.1
3163
    
3164
    4.1.0
3165
    
3166
    2005/12/10
3167
    ----------
3168
    
3169
    Added ``merge``, a recursive update.
3170
    
3171
    Added ``preserve_errors`` to ``validate`` and the ``flatten_errors``
3172
    example function.
3173
    
3174
    Thanks to Matthew Brett for suggestions and helping me iron out bugs.
3175
    
3176
    Fixed bug where a config file is *all* comment, the comment will now be
3177
    ``initial_comment`` rather than ``final_comment``.
3178
    
3179
    2005/12/02
3180
    ----------
3181
    
3182
    Fixed bug in ``create_empty``. Thanks to Paul Jimenez for the report.
3183
    
3184
    2005/11/04
3185
    ----------
3186
    
3187
    Fixed bug in ``Section.walk`` when transforming names as well as values.
3188
    
3189
    Added the ``istrue`` method. (Fetches the boolean equivalent of a string
3190
    value).
3191
    
3192
    Fixed ``list_values=False`` - they are now only quoted/unquoted if they
3193
    are multiline values.
3194
    
3195
    List values are written as ``item, item`` rather than ``item,item``.
3196
    
3197
    4.0.1
3198
    
1185.12.49 by Aaron Bentley
Switched to ConfigObj
3199
    2005/10/09
3200
    ----------
3201
    
3202
    Fixed typo in ``write`` method. (Testing for the wrong value when resetting
3203
    ``interpolation``).
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
3204
3205
    4.0.0 Final
1185.12.49 by Aaron Bentley
Switched to ConfigObj
3206
    
3207
    2005/09/16
3208
    ----------
3209
    
3210
    Fixed bug in ``setdefault`` - creating a new section *wouldn't* return
3211
    a reference to the new section.
3212
    
3213
    2005/09/09
3214
    ----------
3215
    
3216
    Removed ``PositionError``.
3217
    
3218
    Allowed quotes around keys as documented.
3219
    
3220
    Fixed bug with commas in comments. (matched as a list value)
3221
    
3222
    Beta 5
3223
    
3224
    2005/09/07
3225
    ----------
3226
    
3227
    Fixed bug in initialising ConfigObj from a ConfigObj.
3228
    
3229
    Changed the mailing list address.
3230
    
3231
    Beta 4
3232
    
3233
    2005/09/03
3234
    ----------
3235
    
1556.2.1 by Aaron Bentley
Switched to ConfigObj 4.2.0
3236
    Fixed bug in ``Section.__delitem__`` oops.
1185.12.49 by Aaron Bentley
Switched to ConfigObj
3237
    
3238
    2005/08/28
3239
    ----------
3240
    
3241
    Interpolation is switched off before writing out files.
3242
    
3243
    Fixed bug in handling ``StringIO`` instances. (Thanks to report from
3244
    "Gustavo Niemeyer" <gustavo@niemeyer.net>)
3245
    
3246
    Moved the doctests from the ``__init__`` method to a separate function.
3247
    (For the sake of IDE calltips).
3248
    
3249
    Beta 3
3250
    
3251
    2005/08/26
3252
    ----------
3253
    
3254
    String values unchanged by validation *aren't* reset. This preserves
3255
    interpolation in string values.
3256
    
3257
    2005/08/18
3258
    ----------
3259
    
3260
    None from a default is turned to '' if stringify is off - because setting 
3261
    a value to None raises an error.
3262
    
3263
    Version 4.0.0-beta2
3264
    
3265
    2005/08/16
3266
    ----------
3267
    
3268
    By Nicola Larosa
3269
    
3270
    Actually added the RepeatSectionError class ;-)
3271
    
3272
    2005/08/15
3273
    ----------
3274
    
3275
    If ``stringify`` is off - list values are preserved by the ``validate``
3276
    method. (Bugfix)
3277
    
3278
    2005/08/14
3279
    ----------
3280
    
3281
    By Michael Foord
3282
    
3283
    Fixed ``simpleVal``.
3284
    
3285
    Added ``RepeatSectionError`` error if you have additional sections in a
3286
    section with a ``__many__`` (repeated) section.
3287
    
3288
    By Nicola Larosa
3289
    
3290
    Reworked the ConfigObj._parse, _handle_error and _multiline methods:
3291
    mutated the self._infile, self._index and self._maxline attributes into
3292
    local variables and method parameters
3293
    
3294
    Reshaped the ConfigObj._multiline method to better reflect its semantics
3295
    
3296
    Changed the "default_test" test in ConfigObj.validate to check the fix for
3297
    the bug in validate.Validator.check
3298
    
3299
    2005/08/13
3300
    ----------
3301
    
3302
    By Nicola Larosa
3303
    
3304
    Updated comments at top
3305
    
3306
    2005/08/11
3307
    ----------
3308
    
3309
    By Michael Foord
3310
    
3311
    Implemented repeated sections.
3312
    
3313
    By Nicola Larosa
3314
    
3315
    Added test for interpreter version: raises RuntimeError if earlier than
3316
    2.2
3317
    
3318
    2005/08/10
3319
    ----------
3320
   
3321
    By Michael Foord
3322
     
3323
    Implemented default values in configspecs.
3324
    
3325
    By Nicola Larosa
3326
    
3327
    Fixed naked except: clause in validate that was silencing the fact
3328
    that Python2.2 does not have dict.pop
3329
    
3330
    2005/08/08
3331
    ----------
3332
    
3333
    By Michael Foord
3334
    
3335
    Bug fix causing error if file didn't exist.
3336
    
3337
    2005/08/07
3338
    ----------
3339
    
3340
    By Nicola Larosa
3341
    
3342
    Adjusted doctests for Python 2.2.3 compatibility
3343
    
3344
    2005/08/04
3345
    ----------
3346
    
3347
    By Michael Foord
3348
    
3349
    Added the inline_comments attribute
3350
    
3351
    We now preserve and rewrite all comments in the config file
3352
    
3353
    configspec is now a section attribute
3354
    
3355
    The validate method changes values in place
3356
    
3357
    Added InterpolationError
3358
    
3359
    The errors now have line number, line, and message attributes. This
3360
    simplifies error handling
3361
    
3362
    Added __docformat__
3363
    
3364
    2005/08/03
3365
    ----------
3366
    
3367
    By Michael Foord
3368
    
3369
    Fixed bug in Section.pop (now doesn't raise KeyError if a default value
3370
    is specified)
3371
    
3372
    Replaced ``basestring`` with ``types.StringTypes``
3373
    
3374
    Removed the ``writein`` method
3375
    
3376
    Added __version__
3377
    
3378
    2005/07/29
3379
    ----------
3380
    
3381
    By Nicola Larosa
3382
    
3383
    Indentation in config file is not significant anymore, subsections are
3384
    designated by repeating square brackets
3385
    
3386
    Adapted all tests and docs to the new format
3387
    
3388
    2005/07/28
3389
    ----------
3390
    
3391
    By Nicola Larosa
3392
    
3393
    Added more tests
3394
    
3395
    2005/07/23
3396
    ----------
3397
    
3398
    By Nicola Larosa
3399
    
3400
    Reformatted final docstring in ReST format, indented it for easier folding
3401
    
3402
    Code tests converted to doctest format, and scattered them around
3403
    in various docstrings
3404
    
3405
    Walk method rewritten using scalars and sections attributes
3406
    
3407
    2005/07/22
3408
    ----------
3409
    
3410
    By Nicola Larosa
3411
    
3412
    Changed Validator and SimpleVal "test" methods to "check"
3413
    
3414
    More code cleanup
3415
    
3416
    2005/07/21
3417
    ----------
3418
    
3419
    Changed Section.sequence to Section.scalars and Section.sections
3420
    
3421
    Added Section.configspec
3422
    
3423
    Sections in the root section now have no extra indentation
3424
    
3425
    Comments now better supported in Section and preserved by ConfigObj
3426
    
3427
    Comments also written out
3428
    
3429
    Implemented initial_comment and final_comment
3430
    
3431
    A scalar value after a section will now raise an error
3432
    
3433
    2005/07/20
3434
    ----------
3435
    
3436
    Fixed a couple of bugs
3437
    
3438
    Can now pass a tuple instead of a list
3439
    
3440
    Simplified dict and walk methods
3441
    
3442
    Added __str__ to Section
3443
    
3444
    2005/07/10
3445
    ----------
3446
    
3447
    By Nicola Larosa
3448
    
3449
    More code cleanup
3450
    
3451
    2005/07/08
3452
    ----------
3453
    
3454
    The stringify option implemented. On by default.
3455
    
3456
    2005/07/07
3457
    ----------
3458
    
3459
    Renamed private attributes with a single underscore prefix.
3460
    
3461
    Changes to interpolation - exceeding recursion depth, or specifying a
3462
    missing value, now raise errors.
3463
    
3464
    Changes for Python 2.2 compatibility. (changed boolean tests - removed
3465
    ``is True`` and ``is False``)
3466
    
3467
    Added test for duplicate section and member (and fixed bug)
3468
    
3469
    2005/07/06
3470
    ----------
3471
    
3472
    By Nicola Larosa
3473
    
3474
    Code cleanup
3475
    
3476
    2005/07/02
3477
    ----------
3478
    
3479
    Version 0.1.0
3480
    
3481
    Now properly handles values including comments and lists.
3482
    
3483
    Better error handling.
3484
    
3485
    String interpolation.
3486
    
3487
    Some options implemented.
3488
    
3489
    You can pass a Section a dictionary to initialise it.
3490
    
3491
    Setting a Section member to a dictionary will create a Section instance.
3492
    
3493
    2005/06/26
3494
    ----------
3495
    
3496
    Version 0.0.1
3497
    
3498
    Experimental reader.
3499
    
3500
    A reasonably elegant implementation - a basic reader in 160 lines of code.
3501
    
3502
    *A programming language is a medium of expression.* - Paul Graham
3503
"""
3504