~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Naoki INADA
  • Date: 2009-10-29 10:01:19 UTC
  • mto: (4634.97.3 2.0)
  • mto: This revision was merged to the branch mainline in revision 4798.
  • Revision ID: inada-n@klab.jp-20091029100119-uckv9t7ej2qrghw3
import doc-ja rev90

Show diffs side-by-side

added added

removed removed

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