161
149
'indent_type': None,
162
150
'encoding': None,
163
151
'default_encoding': None,
165
'write_empty_values': False,
173
raise ImportError('compiler module not available')
174
p = compiler.parse(s)
175
return p.getChildren()[1].getChildren()[0].getChildren()[1]
178
class UnknownType(Exception):
182
class Builder(object):
185
m = getattr(self, 'build_' + o.__class__.__name__, None)
187
raise UnknownType(o.__class__.__name__)
190
def build_List(self, o):
191
return map(self.build, o.getChildren())
193
def build_Const(self, o):
196
def build_Dict(self, o):
198
i = iter(map(self.build, o.getChildren()))
203
def build_Tuple(self, o):
204
return tuple(self.build_List(o))
206
def build_Name(self, o):
211
if o.name == 'False':
215
raise UnknownType('Undefined Name')
217
def build_Add(self, o):
218
real, imag = map(self.build_Const, o.getChildren())
222
raise UnknownType('Add')
223
if not isinstance(imag, complex) or imag.real != 0.0:
224
raise UnknownType('Add')
227
def build_Getattr(self, o):
228
parent = self.build(o.expr)
229
return getattr(parent, o.attrname)
231
def build_UnarySub(self, o):
232
return -self.build_Const(o.getChildren()[0])
234
def build_UnaryAdd(self, o):
235
return self.build_Const(o.getChildren()[0])
244
return _builder.build(getObj(s))
248
154
class ConfigObjError(SyntaxError):
250
156
This is the base class for all errors that ConfigObj raises.
251
157
It is a subclass of SyntaxError.
159
>>> raise ConfigObjError
160
Traceback (most recent call last):
253
163
def __init__(self, message='', line_number=None, line=''):
255
165
self.line_number = line_number
166
self.message = message
256
167
SyntaxError.__init__(self, message)
259
169
class NestingError(ConfigObjError):
261
171
This error indicates a level of nesting that doesn't match.
173
>>> raise NestingError
174
Traceback (most recent call last):
265
178
class ParseError(ConfigObjError):
267
180
This error indicates that a line is badly written.
268
181
It is neither a valid ``key = value`` line,
269
182
nor a valid section marker line.
273
class ReloadError(IOError):
275
A 'reload' operation failed.
276
This exception is a subclass of ``IOError``.
279
IOError.__init__(self, 'reload failed, filename is not set.')
185
Traceback (most recent call last):
282
189
class DuplicateError(ConfigObjError):
284
191
The keyword or section specified already exists.
193
>>> raise DuplicateError
194
Traceback (most recent call last):
288
198
class ConfigspecError(ConfigObjError):
290
200
An error occured whilst parsing a configspec.
202
>>> raise ConfigspecError
203
Traceback (most recent call last):
294
207
class InterpolationError(ConfigObjError):
295
208
"""Base class for the two interpolation errors."""
298
class InterpolationLoopError(InterpolationError):
210
class InterpolationDepthError(InterpolationError):
299
211
"""Maximum interpolation depth exceeded in string interpolation."""
301
213
def __init__(self, option):
215
>>> raise InterpolationDepthError('yoda')
216
Traceback (most recent call last):
217
InterpolationDepthError: max interpolation depth exceeded in value "yoda".
302
219
InterpolationError.__init__(
304
'interpolation loop detected in value "%s".' % option)
221
'max interpolation depth exceeded in value "%s".' % option)
307
223
class RepeatSectionError(ConfigObjError):
309
225
This error indicates additional sections in a section with a
310
226
``__many__`` (repeated) section.
228
>>> raise RepeatSectionError
229
Traceback (most recent call last):
314
233
class MissingInterpolationOption(InterpolationError):
315
234
"""A value specified for interpolation was missing."""
317
236
def __init__(self, option):
238
>>> raise MissingInterpolationOption('yoda')
239
Traceback (most recent call last):
240
MissingInterpolationOption: missing option "yoda" in interpolation.
318
242
InterpolationError.__init__(
320
244
'missing option "%s" in interpolation.' % option)
323
class UnreprError(ConfigObjError):
324
"""An error parsing in unrepr mode."""
328
class InterpolationEngine(object):
330
A helper class to help perform string interpolation.
332
This class is an abstract base class; its descendants perform
336
# compiled regexp to use in self.interpolate()
337
_KEYCRE = re.compile(r"%\(([^)]*)\)s")
339
def __init__(self, section):
340
# the Section instance that "owns" this engine
341
self.section = section
344
def interpolate(self, key, value):
345
def recursive_interpolate(key, value, section, backtrail):
346
"""The function that does the actual work.
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
353
This is similar to a depth-first-search algorithm.
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
362
# Now start the actual work
363
match = self._KEYCRE.search(value)
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)
369
# That's the signal that no further interpolation is needed
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)
382
# Now safe to come back here again; remove marker from backtrail
383
del backtrail[(key, section.name)]
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, {})
393
def _fetch(self, key):
394
"""Helper function to fetch values from owning section.
396
Returns a 2-tuple: the value, and the section where it was found.
398
# switch off interpolation before we try and fetch anything !
399
save_interp = self.section.main.interpolation
400
self.section.main.interpolation = False
402
# Start at section that "owns" this InterpolationEngine
403
current_section = self.section
405
# try the current section first
406
val = current_section.get(key)
410
val = current_section.get('DEFAULT', {}).get(key)
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
418
current_section = current_section.parent
420
# restore interpolation to previous value before returning
421
self.section.main.interpolation = save_interp
423
raise MissingInterpolationOption(key)
424
return val, current_section
427
def _parse_match(self, match):
428
"""Implementation-dependent helper function.
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)
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
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 "$").
443
raise NotImplementedError()
447
class ConfigParserInterpolation(InterpolationEngine):
448
"""Behaves like ConfigParser."""
449
_KEYCRE = re.compile(r"%\(([^)]*)\)s")
451
def _parse_match(self, match):
453
value, section = self._fetch(key)
454
return key, value, section
458
class TemplateInterpolation(InterpolationEngine):
459
"""Behaves like string.Template."""
461
_KEYCRE = re.compile(r"""
463
(?P<escaped>\$) | # Two $ signs
464
(?P<named>[_a-z][_a-z0-9]*) | # $name format
465
{(?P<braced>[^}]*)} # ${name} format
467
""", re.IGNORECASE | re.VERBOSE)
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')
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
483
interpolation_engines = {
484
'configparser': ConfigParserInterpolation,
485
'template': TemplateInterpolation,
489
def __newobj__(cls, *args):
491
return cls.__new__(cls, *args)
493
246
class Section(dict):
495
248
A dictionary-like object that represents a section in a config file.
497
It does string interpolation if the 'interpolation' attribute
250
It does string interpolation if the 'interpolate' attribute
498
251
of the 'main' object is set to True.
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.
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.
504
256
A Section will behave like an ordered dictionary - following the
505
257
order of the ``scalars`` and ``sections`` attributes.
506
258
You can use this to change the order of members.
508
260
Iteration follows the order: scalars, then sections.
512
def __setstate__(self, state):
513
dict.update(self, state[0])
514
self.__dict__.update(state[1])
516
def __reduce__(self):
517
state = (dict(self), self.__dict__)
518
return (__newobj__, (self.__class__,), state)
263
_KEYCRE = re.compile(r"%\(([^)]*)\)s|.")
521
265
def __init__(self, parent, depth, main, indict=None, name=None):
535
279
# level of nesting depth of this Section
536
280
self.depth = depth
281
# the sequence of scalar values in this Section
283
# the sequence of sections in this Section
537
285
# purely for information
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():
547
def _initialise(self):
548
# the sequence of scalar values in this Section
550
# the sequence of sections in this Section
552
287
# for comments :-)
553
288
self.comments = {}
554
289
self.inline_comments = {}
556
self.configspec = None
558
293
self.defaults = []
559
self.default_values = {}
562
def _interpolate(self, key, value):
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)
575
# invalid value for self.main.interpolation
576
self.main.interpolation = False
295
# we do this explicitly so that __setitem__ is used properly
296
# (rather than just passing to ``dict.__init__``)
298
self[entry] = indict[entry]
300
def _interpolate(self, value):
301
"""Nicked from ConfigParser."""
302
depth = MAX_INTERPOL_DEPTH
303
# loop through this until it's done
306
if value.find("%(") != -1:
307
value = self._KEYCRE.sub(self._interpolation_replace, 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)
311
raise InterpolationDepthError(value)
314
def _interpolation_replace(self, match):
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
326
val = self.parent.get('DEFAULT', {}).get(s)
327
# last, try the 'DEFAULT' member of the *main section*
329
val = self.main.get('DEFAULT', {}).get(s)
330
self.main.interpolation = True
332
raise MissingInterpolationOption(s)
585
335
def __getitem__(self, key):
586
336
"""Fetch the item and do string interpolation."""
587
337
val = dict.__getitem__(self, key)
588
if self.main.interpolation and isinstance(val, basestring):
589
return self._interpolate(key, val)
338
if self.main.interpolation and isinstance(val, StringTypes):
339
return self._interpolate(val)
593
def __setitem__(self, key, value, unrepr=False):
342
def __setitem__(self, key, value):
595
344
Correctly set a value.
597
346
Making dictionary values Section instances.
598
347
(We have to special case 'Section' instances - which are also dicts)
600
349
Keys must be strings.
601
350
Values need only be strings (or lists of strings) if
602
351
``main.stringify`` is set.
604
``unrepr`` must be set when setting a value to a dictionary, without
605
creating a new sub-section.
607
if not isinstance(key, basestring):
608
raise ValueError('The key "%s" is not a string.' % key)
353
if not isinstance(key, StringTypes):
354
raise ValueError, 'The key "%s" is not a string.' % key
610
355
# add the comment
611
356
if key not in self.comments:
612
357
self.comments[key] = []
667
def decode(self, encoding):
669
Decode all strings and values to unicode, using the specified encoding.
671
Works with subsections and list values.
673
Uses the ``walk`` method.
675
Testing ``encode`` and ``decode``.
677
>>> m.decode('ascii')
678
>>> def testuni(val):
679
... for entry in val:
680
... if not isinstance(entry, unicode):
681
... print >> sys.stderr, type(entry)
682
... raise AssertionError, 'decode failed.'
683
... if isinstance(val[entry], dict):
684
... testuni(val[entry])
685
... elif not isinstance(val[entry], unicode):
686
... raise AssertionError, 'decode failed.'
688
>>> m.encode('ascii')
692
def decode(section, key, encoding=encoding):
695
if isinstance(val, (list, tuple)):
698
newval.append(entry.decode(encoding))
699
elif isinstance(val, dict):
702
newval = val.decode(encoding)
703
newkey = key.decode(encoding)
704
section.rename(key, newkey)
705
section[newkey] = newval
706
# using ``call_on_sections`` allows us to modify section names
707
self.walk(decode, call_on_sections=True)
709
def encode(self, encoding):
711
Encode all strings and values from unicode,
712
using the specified encoding.
714
Works with subsections and list values.
715
Uses the ``walk`` method.
717
def encode(section, key, encoding=encoding):
720
if isinstance(val, (list, tuple)):
723
newval.append(entry.encode(encoding))
724
elif isinstance(val, dict):
727
newval = val.encode(encoding)
728
newkey = key.encode(encoding)
729
section.rename(key, newkey)
730
section[newkey] = newval
731
self.walk(encode, call_on_sections=True)
733
def istrue(self, key):
734
"""A deprecated version of ``as_bool``."""
735
warn('use of ``istrue`` is deprecated. Use ``as_bool`` method '
736
'instead.', DeprecationWarning)
737
return self.as_bool(key)
947
739
def as_bool(self, key):
949
741
Accepts a key as input. The corresponding value must be a string or
950
742
the objects (``True`` or 1) or (``False`` or 0). We allow 0 and 1 to
951
743
retain compatibility with Python 2.2.
953
If the string is one of ``True``, ``On``, ``Yes``, or ``1`` it returns
745
If the string is one of ``True``, ``On``, ``Yes``, or ``1`` it returns
956
If the string is one of ``False``, ``Off``, ``No``, or ``0`` it returns
748
If the string is one of ``False``, ``Off``, ``No``, or ``0`` it returns
959
751
``as_bool`` is not case sensitive.
961
753
Any other input will raise a ``ValueError``.
963
755
>>> a = ConfigObj()
964
756
>>> a['a'] = 'fish'
965
757
>>> a.as_bool('a')
1190
950
'true': True, 'false': False,
1194
def __init__(self, infile=None, options=None, _inspec=False, **kwargs):
953
def __init__(self, infile=None, options=None, **kwargs):
1196
Parse a config file or create a config file object.
955
Parse or create a config file object.
1198
957
``ConfigObj(infile=None, options=None, **kwargs)``
1200
self._inspec = _inspec
963
# keyword arguments take precedence over an options dictionary
964
options.update(kwargs)
1201
965
# init the superclass
1202
966
Section.__init__(self, self, 0, self)
1204
infile = infile or []
1205
options = dict(options or {})
1207
# keyword arguments take precedence over an options dictionary
1208
options.update(kwargs)
1210
options['list_values'] = False
1212
968
defaults = OPTION_DEFAULTS.copy()
969
for entry in options.keys():
970
if entry not in defaults.keys():
971
raise TypeError, 'Unrecognised option "%s".' % entry
1213
972
# TODO: check the values too.
1214
for entry in options:
1215
if entry not in defaults:
1216
raise TypeError('Unrecognised option "%s".' % entry)
1218
974
# Add any explicit options to the defaults
1219
975
defaults.update(options)
1220
self._initialise(defaults)
1221
configspec = defaults['configspec']
1222
self._original_configspec = configspec
1223
self._load(infile, configspec)
1226
def _load(self, infile, configspec):
1227
if isinstance(infile, basestring):
977
# initialise a few variables
980
self.raise_errors = defaults['raise_errors']
981
self.interpolation = defaults['interpolation']
982
self.list_values = defaults['list_values']
983
self.create_empty = defaults['create_empty']
984
self.file_error = defaults['file_error']
985
self.stringify = defaults['stringify']
986
self.indent_type = defaults['indent_type']
987
self.encoding = defaults['encoding']
988
self.default_encoding = defaults['default_encoding']
992
self.initial_comment = []
993
self.final_comment = []
995
if isinstance(infile, StringTypes):
1228
996
self.filename = infile
1229
997
if os.path.isfile(infile):
1230
h = open(infile, 'rb')
1231
infile = h.read() or []
998
infile = open(infile).read() or []
1233
999
elif self.file_error:
1234
1000
# raise an error if the file doesn't exist
1235
raise IOError('Config file not found: "%s".' % self.filename)
1001
raise IOError, 'Config file not found: "%s".' % self.filename
1237
1003
# file doesn't already exist
1238
1004
if self.create_empty:
1239
1005
# this is a good test that the filename specified
1240
# isn't impossible - like on a non-existent device
1006
# isn't impossible - like on a non existent device
1241
1007
h = open(infile, 'w')
1246
1011
elif isinstance(infile, (list, tuple)):
1247
1012
infile = list(infile)
1249
1013
elif isinstance(infile, dict):
1250
1014
# initialise self
1251
1015
# the Section class handles creating subsections
1252
1016
if isinstance(infile, ConfigObj):
1253
1017
# get a copy of our ConfigObj
1254
1018
infile = infile.dict()
1256
1019
for entry in infile:
1257
1020
self[entry] = infile[entry]
1258
1021
del self._errors
1260
if configspec is not None:
1261
self._handle_configspec(configspec)
1022
if defaults['configspec'] is not None:
1023
self._handle_configspec(defaults['configspec'])
1263
1025
self.configspec = None
1266
elif getattr(infile, 'read', MISSING) is not MISSING:
1027
elif getattr(infile, 'read', None) is not None:
1267
1028
# This supports file like objects
1268
1029
infile = infile.read() or []
1269
1030
# needs splitting into lines - but needs doing *after* decoding
1270
1031
# in case it's not an 8 bit encoding
1272
raise TypeError('infile must be a filename, file like object, or list of lines.')
1033
raise TypeError, ('infile must be a filename,'
1034
' file like object, or list of lines.')
1275
1037
# don't do it for the empty ConfigObj
1276
1038
infile = self._handle_bom(infile)
1605
1382
'Parse error in value at line %s.',
1606
1383
ParseError, infile, cur_index)
1612
value = unrepr(value)
1613
except Exception, e:
1614
if type(e) == UnknownType:
1615
msg = 'Unknown name or type in value at line %s.'
1617
msg = 'Parse error in value at line %s.'
1618
self._handle_error(msg, UnreprError, infile,
1625
value = unrepr(value)
1626
except Exception, e:
1627
if isinstance(e, UnknownType):
1628
msg = 'Unknown name or type in value at line %s.'
1630
msg = 'Parse error in value at line %s.'
1631
self._handle_error(msg, UnreprError, infile,
1635
# extract comment and lists
1637
(value, comment) = self._handle_value(value)
1640
'Parse error in value at line %s.',
1641
ParseError, infile, cur_index)
1386
# extract comment and lists
1388
(value, comment) = self._handle_value(value)
1391
'Parse error in value at line %s.',
1392
ParseError, infile, cur_index)
1395
## print >> sys.stderr, sline
1644
1396
key = self._unquote(key)
1645
1397
if key in this_section:
1646
1398
self._handle_error(
1647
1399
'Duplicate keyword name at line %s.',
1648
1400
DuplicateError, infile, cur_index)
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)
1403
## print >> sys.stderr, this_section.name
1404
this_section[key] = value
1654
1405
this_section.inline_comments[key] = comment
1655
1406
this_section.comments[key] = comment_list
1407
## print >> sys.stderr, key, this_section[key]
1408
## if this_section.name is not None:
1409
## print >> sys.stderr, this_section
1410
## print >> sys.stderr, this_section.parent
1411
## print >> sys.stderr, this_section.parent[this_section.name]
1414
# it neither matched as a keyword
1415
# or a section marker
1417
'Invalid line at line "%s".',
1418
ParseError, infile, cur_index)
1658
1419
if self.indent_type is None:
1659
1420
# no indentation used, set the type accordingly
1660
1421
self.indent_type = ''
1662
1422
# preserve the final comment
1663
1423
if not self and not self.initial_comment:
1664
1424
self.initial_comment = comment_list
1665
elif not reset_comment:
1666
1426
self.final_comment = comment_list
1667
self.list_values = temp_list_values
1670
1428
def _match_depth(self, sect, depth):
1672
1430
Given a section and a depth level, walk back through the sections
1673
1431
parents to see if the depth level matches a previous section.
1675
1433
Return a reference to the right section,
1676
1434
or raise a SyntaxError.
1678
1436
while depth < sect.depth:
1679
1437
if sect is sect.parent:
1680
1438
# we've reached the top level already
1682
1440
sect = sect.parent
1683
1441
if sect.depth == depth:
1685
1443
# shouldn't get here
1689
1446
def _handle_error(self, text, ErrorClass, infile, cur_index):
1691
1448
Handle an error according to the error settings.
1693
1450
Either raise the error or store it.
1694
1451
The error will have occured at ``cur_index``
1704
1461
# reraise when parsing has finished
1705
1462
self._errors.append(error)
1708
1464
def _unquote(self, value):
1709
1465
"""Return an unquoted version of a value"""
1710
1466
if (value[0] == value[-1]) and (value[0] in ('"', "'")):
1711
1467
value = value[1:-1]
1715
1470
def _quote(self, value, multiline=True):
1717
1472
Return a safely quoted version of a value.
1719
1474
Raise a ConfigObjError if the value cannot be safely quoted.
1720
1475
If multiline is ``True`` (default) then use triple quotes
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.
1478
Don't quote values that don't need it.
1479
Recursively quote members of a list and return a comma joined list.
1480
Multiline is ``False`` for lists.
1481
Obey list syntax for empty and single member lists.
1728
1483
If ``list_values=False`` then the value is only quoted if it contains
1729
a ``\\n`` (is multiline) or '#'.
1731
If ``write_empty_values`` is set, and the value is an empty string, it
1484
a ``\n`` (is multiline).
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
1739
if multiline and isinstance(value, (list, tuple)):
1486
if isinstance(value, (list, tuple)):
1742
1489
elif len(value) == 1:
1743
1490
return self._quote(value[0], multiline=False) + ','
1744
1491
return ', '.join([self._quote(val, multiline=False)
1745
1492
for val in value])
1746
if not isinstance(value, basestring):
1493
if not isinstance(value, StringTypes):
1747
1494
if self.stringify:
1748
1495
value = str(value)
1750
raise TypeError('Value "%s" is not a string.' % value)
1497
raise TypeError, 'Value "%s" is not a string.' % value
1501
wspace_plus = ' \r\t\n\v\t\'"'
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
1760
if check_for_single:
1506
if (not self.list_values and '\n' not in value) or not (multiline and
1507
((("'" in value) and ('"' in value)) or ('\n' in value))):
1761
1508
if not self.list_values:
1762
1509
# we don't quote if ``list_values=False``
1764
1511
# for normal values either single or double quotes will do
1765
1512
elif '\n' in value:
1766
1513
# will only happen if multiline is off - e.g. '\n' in key
1767
raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
1514
raise ConfigObjError, ('Value "%s" cannot be safely quoted.' %
1768
1516
elif ((value[0] not in wspace_plus) and
1769
1517
(value[-1] not in wspace_plus) and
1770
1518
(',' not in value)):
1773
quot = self._get_single_quote(value)
1521
if ("'" in value) and ('"' in value):
1522
raise ConfigObjError, (
1523
'Value "%s" cannot be safely quoted.' % value)
1775
1529
# if value has '\n' or "'" *and* '"', it will need triple quotes
1776
quot = self._get_triple_quote(value)
1778
if quot == noquot and '#' in value and self.list_values:
1779
quot = self._get_single_quote(value)
1530
if (value.find('"""') != -1) and (value.find("'''") != -1):
1531
raise ConfigObjError, (
1532
'Value "%s" cannot be safely quoted.' % value)
1533
if value.find('"""') == -1:
1781
1537
return quot % value
1784
def _get_single_quote(self, value):
1785
if ("'" in value) and ('"' in value):
1786
raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
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
# upstream version (up to version 4.7.2) has the bug with incorrect quoting;
1798
# fixed in our copy based on the suggestion of ConfigObj's author
1799
if value.find('"""') == -1:
1806
1539
def _handle_value(self, value):
1808
1541
Given a value string, unquote, remove comment,
1809
1542
handle lists. (including empty and single member lists)
1544
Testing list values.
1546
>>> testconfig3 = '''
1549
... c = test1, test2 , test3
1550
... d = test1, test2, test3,
1552
>>> d = ConfigObj(testconfig3.split('\\n'), raise_errors=True)
1555
>>> d['b'] == ['test']
1557
>>> d['c'] == ['test1', 'test2', 'test3']
1559
>>> d['d'] == ['test1', 'test2', 'test3']
1562
Testing with list values off.
1565
... testconfig3.split('\\n'),
1566
... raise_errors=True,
1567
... list_values=False)
1570
>>> e['b'] == 'test,'
1572
>>> e['c'] == 'test1, test2 , test3'
1574
>>> e['d'] == 'test1, test2, test3,'
1577
Testing creating from a dictionary.
1600
>>> g = ConfigObj(f)
1604
Testing we correctly detect badly built list values (4 of them).
1606
>>> testconfig4 = '''
1610
... dummy = ,,hello, goodbye
1613
... ConfigObj(testconfig4.split('\\n'))
1614
... except ConfigObjError, e:
1618
Testing we correctly detect badly quoted values (4 of them).
1620
>>> testconfig5 = '''
1621
... config = "hello # comment
1623
... fish = 'goodbye # comment
1624
... dummy = "hello again
1627
... ConfigObj(testconfig5.split('\\n'))
1628
... except ConfigObjError, e:
1812
# Parsing a configspec so don't handle comments
1814
1632
# do we look for lists in values ?
1815
1633
if not self.list_values:
1816
1634
mat = self._nolistvalue.match(value)
1817
1635
if mat is None:
1637
(value, comment) = mat.groups()
1819
1638
# NOTE: we don't unquote here
1639
return (value, comment)
1822
1640
mat = self._valueexp.match(value)
1823
1641
if mat is None:
1824
1642
# the value is badly constructed, probably badly quoted,
1825
1643
# or an invalid list
1827
1645
(list_values, single, empty_list, comment) = mat.groups()
1828
1646
if (list_values == '') and (single is None):
1829
1647
# change this if you want to accept empty values
1831
1649
# NOTE: note there is no error handling from here if the regex
1832
1650
# is wrong: then incorrect values will slip through
1833
1651
if empty_list is not None:
1834
1652
# the single comma - meaning an empty list
1835
1653
return ([], comment)
1836
1654
if single is not None:
1837
# handle empty values
1838
if list_values and not single:
1839
# FIXME: the '' is a workaround because our regex now matches
1840
# '' at the end of a list if it has a trailing comma
1843
single = single or '""'
1844
single = self._unquote(single)
1655
single = self._unquote(single)
1845
1656
if list_values == '':
1846
1657
# not a list value
1847
1658
return (single, comment)
1880
1712
# we've got to the end of the config, oops...
1882
1714
mat = multi_line.match(line)
1883
1715
if mat is None:
1884
1716
# a badly formed line
1886
1718
(value, comment) = mat.groups()
1887
1719
return (newvalue + value, comment, cur_index)
1890
1721
def _handle_configspec(self, configspec):
1891
1722
"""Parse the configspec."""
1892
# FIXME: Should we check that the configspec was created with the
1893
# correct settings ? (i.e. ``list_values=False``)
1894
if not isinstance(configspec, ConfigObj):
1896
configspec = ConfigObj(configspec,
1900
except ConfigObjError, e:
1901
# FIXME: Should these errors have a reference
1902
# to the already parsed ConfigObj ?
1903
raise ConfigspecError('Parsing configspec failed: %s' % e)
1905
raise IOError('Reading configspec failed: %s' % e)
1907
self.configspec = configspec
1911
def _set_configspec(self, section, copy):
1913
Called by validate. Handles setting the configspec on subsections
1914
including sections to be validated by __many__
1916
configspec = section.configspec
1917
many = configspec.get('__many__')
1918
if isinstance(many, dict):
1919
for entry in section.sections:
1920
if entry not in configspec:
1921
section[entry].configspec = many
1724
configspec = ConfigObj(
1729
except ConfigObjError, e:
1730
# FIXME: Should these errors have a reference
1731
# to the already parsed ConfigObj ?
1732
raise ConfigspecError('Parsing configspec failed: %s' % e)
1734
raise IOError('Reading configspec failed: %s' % e)
1735
self._set_configspec_value(configspec, self)
1737
def _set_configspec_value(self, configspec, section):
1738
"""Used to recursively set configspec values."""
1739
if '__many__' in configspec.sections:
1740
section.configspec['__many__'] = configspec['__many__']
1741
if len(configspec.sections) > 1:
1742
# FIXME: can we supply any useful information here ?
1743
raise RepeatSectionError
1744
for entry in configspec.scalars:
1745
section.configspec[entry] = configspec[entry]
1923
1746
for entry in configspec.sections:
1924
1747
if entry == '__many__':
1926
1749
if entry not in section:
1927
1750
section[entry] = {}
1930
section.comments[entry] = configspec.comments.get(entry, [])
1931
section.inline_comments[entry] = configspec.inline_comments.get(entry, '')
1933
# Could be a scalar when we expect a section
1934
if isinstance(section[entry], Section):
1935
section[entry].configspec = configspec[entry]
1751
self._set_configspec_value(configspec[entry], section[entry])
1753
def _handle_repeat(self, section, configspec):
1754
"""Dynamically assign configspec for repeated section."""
1756
section_keys = configspec.sections
1757
scalar_keys = configspec.scalars
1758
except AttributeError:
1759
section_keys = [entry for entry in configspec
1760
if isinstance(configspec[entry], dict)]
1761
scalar_keys = [entry for entry in configspec
1762
if not isinstance(configspec[entry], dict)]
1763
if '__many__' in section_keys and len(section_keys) > 1:
1764
# FIXME: can we supply any useful information here ?
1765
raise RepeatSectionError
1768
for entry in scalar_keys:
1769
val = configspec[entry]
1770
scalars[entry] = val
1771
for entry in section_keys:
1772
val = configspec[entry]
1773
if entry == '__many__':
1774
scalars[entry] = val
1776
sections[entry] = val
1778
section.configspec = scalars
1779
for entry in sections:
1780
if entry not in section:
1782
self._handle_repeat(section[entry], sections[entry])
1938
1784
def _write_line(self, indent_string, entry, this_entry, comment):
1939
1785
"""Write an individual line, for the write method"""
1940
1786
# NOTE: the calls to self._quote here handles non-StringType values.
1942
val = self._decode_element(self._quote(this_entry))
1944
val = repr(this_entry)
1945
return '%s%s%s%s%s' % (indent_string,
1946
self._decode_element(self._quote(entry, multiline=False)),
1947
self._a_to_u(' = '),
1949
self._decode_element(comment))
1787
return '%s%s%s%s%s' % (
1789
self._decode_element(self._quote(entry, multiline=False)),
1790
self._a_to_u(' = '),
1791
self._decode_element(self._quote(this_entry)),
1792
self._decode_element(comment))
1952
1794
def _write_marker(self, indent_string, depth, entry, comment):
1953
1795
"""Write a section marker line"""
1954
return '%s%s%s%s%s' % (indent_string,
1955
self._a_to_u('[' * depth),
1956
self._quote(self._decode_element(entry), multiline=False),
1957
self._a_to_u(']' * depth),
1958
self._decode_element(comment))
1796
return '%s%s%s%s%s' % (
1798
self._a_to_u('[' * depth),
1799
self._quote(self._decode_element(entry), multiline=False),
1800
self._a_to_u(']' * depth),
1801
self._decode_element(comment))
1961
1803
def _handle_comment(self, comment):
1962
"""Deal with a comment."""
1805
Deal with a comment.
1807
>>> filename = a.filename
1808
>>> a.filename = None
1809
>>> values = a.write()
1811
>>> while index < 23:
1813
... line = values[index-1]
1814
... assert line.endswith('# comment ' + str(index))
1815
>>> a.filename = filename
1817
>>> start_comment = ['# Initial Comment', '', '#']
1818
>>> end_comment = ['', '#', '# Final Comment']
1819
>>> newconfig = start_comment + testconfig1.split('\\n') + end_comment
1820
>>> nc = ConfigObj(newconfig)
1821
>>> nc.initial_comment
1822
['# Initial Comment', '', '#']
1823
>>> nc.final_comment
1824
['', '#', '# Final Comment']
1825
>>> nc.initial_comment == start_comment
1827
>>> nc.final_comment == end_comment
1963
1830
if not comment:
1965
start = self.indent_type
1832
if self.indent_type == '\t':
1833
start = self._a_to_u('\t')
1835
start = self._a_to_u(' ' * NUM_INDENT_SPACES)
1966
1836
if not comment.startswith('#'):
1967
start += self._a_to_u(' # ')
1837
start += _a_to_u('# ')
1968
1838
return (start + comment)
1840
def _compute_indent_string(self, depth):
1842
Compute the indent string, according to current indent_type and depth
1844
if self.indent_type == '':
1845
# no indentation at all
1847
if self.indent_type == '\t':
1849
if self.indent_type == ' ':
1850
return ' ' * NUM_INDENT_SPACES * depth
1971
1853
# Public methods
1973
1855
def write(self, outfile=None, section=None):
1975
1857
Write the current ConfigObj as a file
1977
1859
tekNico: FIXME: use StringIO instead of real files
1979
1861
>>> filename = a.filename
1980
1862
>>> a.filename = 'test.ini'
1982
1864
>>> a.filename = filename
1983
1865
>>> a == ConfigObj('test.ini', raise_errors=True)
1867
>>> os.remove('test.ini')
1868
>>> b.filename = 'test.ini'
1870
>>> b == ConfigObj('test.ini', raise_errors=True)
1872
>>> os.remove('test.ini')
1873
>>> i.filename = 'test.ini'
1875
>>> i == ConfigObj('test.ini', raise_errors=True)
1877
>>> os.remove('test.ini')
1879
>>> a['DEFAULT'] = {'a' : 'fish'}
1880
>>> a['a'] = '%(a)s'
1882
['a = %(a)s', '[DEFAULT]', 'a = fish']
1986
1884
if self.indent_type is None:
1987
1885
# this can be true if initialised from a dictionary
1988
1886
self.indent_type = DEFAULT_INDENT_TYPE
1991
1889
cs = self._a_to_u('#')
1992
1890
csp = self._a_to_u('# ')
2055
1954
out[0] = BOM_UTF8 + out[0]
2058
1957
# Turn the list to a string, joined with correct newlines
2059
newline = self.newlines or os.linesep
2060
output = self._a_to_u(newline).join(out)
1958
output = (self._a_to_u(self.newlines or os.linesep)
2061
1960
if self.encoding:
2062
1961
output = output.encode(self.encoding)
2063
if self.BOM and ((self.encoding is None) or match_utf8(self.encoding)):
1962
if (self.BOM and ((self.encoding is None) or
1963
(BOM_LIST.get(self.encoding.lower()) == 'utf_8'))):
2064
1964
# Add the UTF8 BOM
2065
1965
output = BOM_UTF8 + output
2067
if not output.endswith(newline):
2069
1966
if outfile is not None:
2070
1967
outfile.write(output)
2072
h = open(self.filename, 'wb')
1969
h = open(self.filename, 'w')
2073
1970
h.write(output)
2077
def validate(self, validator, preserve_errors=False, copy=False,
1973
def validate(self, validator, preserve_errors=False, section=None):
2080
1975
Test the ConfigObj against a configspec.
2082
1977
It uses the ``validator`` object from *validate.py*.
2084
1979
To run ``validate`` on the current ConfigObj, call: ::
2086
1981
test = config.validate(validator)
2088
1983
(Normally having previously passed in the configspec when the ConfigObj
2089
1984
was created - you can dynamically assign a dictionary of checks to the
2090
1985
``configspec`` attribute of a section though).
2092
1987
It returns ``True`` if everything passes, or a dictionary of
2093
1988
pass/fails (True/False). If every member of a subsection passes, it
2094
1989
will just have the value ``True``. (It also returns ``False`` if all
2097
1992
In addition, it converts the values from strings to their native
2098
1993
types if their checks pass (and ``stringify`` is set).
2100
1995
If ``preserve_errors`` is ``True`` (``False`` is default) then instead
2101
1996
of a marking a fail with a ``False``, it will preserve the actual
2102
1997
exception object. This can contain info about the reason for failure.
2103
For example the ``VdtValueTooSmallError`` indicates that the value
1998
For example the ``VdtValueTooSmallError`` indeicates that the value
2104
1999
supplied was too small. If a value (or section) is missing it will
2105
2000
still be marked as ``False``.
2107
2002
You must have the validate module to use ``preserve_errors=True``.
2109
2004
You can then use the ``flatten_errors`` function to turn your nested
2110
2005
results dictionary into a flattened list of failures - useful for
2111
2006
displaying meaningful error messages.
2009
... from validate import Validator
2010
... except ImportError:
2011
... print >> sys.stderr, 'Cannot import the Validator object, skipping the related tests'
2028
... '''.split('\\n')
2029
... configspec = '''
2030
... test1= integer(30,50)
2033
... test4=float(6.0)
2035
... test1=integer(30,50)
2038
... test4=float(6.0)
2040
... test1=integer(30,50)
2043
... test4=float(6.0)
2044
... '''.split('\\n')
2045
... val = Validator()
2046
... c1 = ConfigObj(config, configspec=configspec)
2047
... test = c1.validate(val)
2058
... 'sub section': {
2067
>>> val.check(c1.configspec['test4'], c1['test4'])
2068
Traceback (most recent call last):
2069
VdtValueTooSmallError: the value "5.0" is too small.
2071
>>> val_test_config = '''
2076
... key2 = 1.1, 3.0, 17, 6.8
2079
... key2 = True'''.split('\\n')
2080
>>> val_test_configspec = '''
2085
... key2 = float_list(4)
2087
... key = option(option1, option2)
2088
... key2 = boolean'''.split('\\n')
2089
>>> val_test = ConfigObj(val_test_config, configspec=val_test_configspec)
2090
>>> val_test.validate(val)
2092
>>> val_test['key'] = 'text not a digit'
2093
>>> val_res = val_test.validate(val)
2094
>>> val_res == {'key2': True, 'section': True, 'key': False}
2096
>>> configspec = '''
2097
... test1=integer(30,50, default=40)
2098
... test2=string(default="hello")
2099
... test3=integer(default=3)
2100
... test4=float(6.0, default=6.0)
2102
... test1=integer(30,50, default=40)
2103
... test2=string(default="hello")
2104
... test3=integer(default=3)
2105
... test4=float(6.0, default=6.0)
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
... '''.split('\\n')
2112
>>> default_test = ConfigObj(['test1=30'], configspec=configspec)
2114
{'test1': '30', 'section': {'sub section': {}}}
2115
>>> default_test.validate(val)
2117
>>> default_test == {
2119
... 'test2': 'hello',
2124
... 'test2': 'hello',
2127
... 'sub section': {
2130
... 'test2': 'hello',
2137
Now testing with repeated sections : BIG TEST
2139
>>> repeated_1 = '''
2141
... [[__many__]] # spec for a dog
2142
... fleas = boolean(default=True)
2143
... tail = option(long, short, default=long)
2144
... name = string(default=rover)
2145
... [[[__many__]]] # spec for a puppy
2146
... name = string(default="son of rover")
2147
... age = float(default=0.0)
2149
... [[__many__]] # spec for a cat
2150
... fleas = boolean(default=True)
2151
... tail = option(long, short, default=short)
2152
... name = string(default=pussy)
2153
... [[[__many__]]] # spec for a kitten
2154
... name = string(default="son of pussy")
2155
... age = float(default=0.0)
2156
... '''.split('\\n')
2157
>>> repeated_2 = '''
2160
... # blank dogs with puppies
2161
... # should be filled in by the configspec
2176
... # blank cats with kittens
2177
... # should be filled in by the configspec
2190
... '''.split('\\n')
2191
>>> repeated_3 = '''
2202
... '''.split('\\n')
2203
>>> repeated_4 = '''
2206
... name = string(default=Michael)
2207
... age = float(default=0.0)
2208
... sex = option(m, f, default=m)
2209
... '''.split('\\n')
2210
>>> repeated_5 = '''
2213
... fleas = boolean(default=True)
2214
... tail = option(long, short, default=short)
2215
... name = string(default=pussy)
2216
... [[[description]]]
2217
... height = float(default=3.3)
2218
... weight = float(default=6)
2220
... fur = option(black, grey, brown, "tortoise shell", default=black)
2221
... condition = integer(0,10, default=5)
2222
... '''.split('\\n')
2223
>>> from validate import Validator
2224
>>> val= Validator()
2225
>>> repeater = ConfigObj(repeated_2, configspec=repeated_1)
2226
>>> repeater.validate(val)
2233
... 'name': 'rover',
2234
... 'puppy1': {'name': 'son of rover', 'age': 0.0},
2235
... 'puppy2': {'name': 'son of rover', 'age': 0.0},
2236
... 'puppy3': {'name': 'son of rover', 'age': 0.0},
2241
... 'name': 'rover',
2242
... 'puppy1': {'name': 'son of rover', 'age': 0.0},
2243
... 'puppy2': {'name': 'son of rover', 'age': 0.0},
2244
... 'puppy3': {'name': 'son of rover', 'age': 0.0},
2249
... 'name': 'rover',
2250
... 'puppy1': {'name': 'son of rover', 'age': 0.0},
2251
... 'puppy2': {'name': 'son of rover', 'age': 0.0},
2252
... 'puppy3': {'name': 'son of rover', 'age': 0.0},
2258
... 'tail': 'short',
2259
... 'name': 'pussy',
2260
... 'kitten1': {'name': 'son of pussy', 'age': 0.0},
2261
... 'kitten2': {'name': 'son of pussy', 'age': 0.0},
2262
... 'kitten3': {'name': 'son of pussy', 'age': 0.0},
2266
... 'tail': 'short',
2267
... 'name': 'pussy',
2268
... 'kitten1': {'name': 'son of pussy', 'age': 0.0},
2269
... 'kitten2': {'name': 'son of pussy', 'age': 0.0},
2270
... 'kitten3': {'name': 'son of pussy', 'age': 0.0},
2274
... 'tail': 'short',
2275
... 'name': 'pussy',
2276
... 'kitten1': {'name': 'son of pussy', 'age': 0.0},
2277
... 'kitten2': {'name': 'son of pussy', 'age': 0.0},
2278
... 'kitten3': {'name': 'son of pussy', 'age': 0.0},
2283
>>> repeater = ConfigObj(repeated_3, configspec=repeated_1)
2284
>>> repeater.validate(val)
2288
... 'cat1': {'fleas': True, 'tail': 'short', 'name': 'pussy'},
2289
... 'cat2': {'fleas': True, 'tail': 'short', 'name': 'pussy'},
2290
... 'cat3': {'fleas': True, 'tail': 'short', 'name': 'pussy'},
2293
... 'dog1': {'fleas': True, 'tail': 'long', 'name': 'rover'},
2294
... 'dog2': {'fleas': True, 'tail': 'long', 'name': 'rover'},
2295
... 'dog3': {'fleas': True, 'tail': 'long', 'name': 'rover'},
2299
>>> repeater = ConfigObj(configspec=repeated_4)
2300
>>> repeater['Michael'] = {}
2301
>>> repeater.validate(val)
2304
... 'Michael': {'age': 0.0, 'name': 'Michael', 'sex': 'm'},
2307
>>> repeater = ConfigObj(repeated_3, configspec=repeated_5)
2309
... 'dogs': {'dog1': {}, 'dog2': {}, 'dog3': {}},
2310
... 'cats': {'cat1': {}, 'cat2': {}, 'cat3': {}},
2313
>>> repeater.validate(val)
2316
... 'dogs': {'dog1': {}, 'dog2': {}, 'dog3': {}},
2320
... 'tail': 'short',
2321
... 'name': 'pussy',
2322
... 'description': {
2324
... 'height': 3.2999999999999998,
2325
... 'coat': {'fur': 'black', 'condition': 5},
2330
... 'tail': 'short',
2331
... 'name': 'pussy',
2332
... 'description': {
2334
... 'height': 3.2999999999999998,
2335
... 'coat': {'fur': 'black', 'condition': 5},
2340
... 'tail': 'short',
2341
... 'name': 'pussy',
2342
... 'description': {
2344
... 'height': 3.2999999999999998,
2345
... 'coat': {'fur': 'black', 'condition': 5},
2352
Test that interpolation is preserved for validated string values.
2353
Also check that interpolation works in configspecs.
2355
>>> t['DEFAULT'] = {}
2356
>>> t['DEFAULT']['test'] = 'a'
2357
>>> t['test'] = '%(test)s'
2361
>>> t.configspec = {'test': 'string'}
2364
>>> t.interpolation = False
2366
{'test': '%(test)s', 'DEFAULT': {'test': 'a'}}
2368
... 'interpolated string = string(default="fuzzy-%(man)s")',
2372
>>> c = ConfigObj(configspec=specs)
2375
>>> c['interpolated string']
2378
FIXME: Above tests will fail if we couldn't import Validator (the ones
2379
that don't raise errors will produce different output and still fail as
2113
2382
if section is None:
2114
2383
if self.configspec is None:
2115
raise ValueError('No configspec supplied.')
2384
raise ValueError, 'No configspec supplied.'
2116
2385
if preserve_errors:
2117
# We do this once to remove a top level dependency on the validate module
2118
# Which makes importing configobj faster
2119
from validate import VdtMissingValue
2120
self._vdtMissingValue = VdtMissingValue
2386
if VdtMissingValue is None:
2387
raise ImportError('Missing validate module.')
2125
section.initial_comment = section.configspec.initial_comment
2126
section.final_comment = section.configspec.final_comment
2127
section.encoding = section.configspec.encoding
2128
section.BOM = section.configspec.BOM
2129
section.newlines = section.configspec.newlines
2130
section.indent_type = section.configspec.indent_type
2133
configspec = section.configspec
2134
self._set_configspec(section, copy)
2136
def validate_entry(entry, spec, val, missing, ret_true, ret_false):
2390
spec_section = section.configspec
2391
if '__many__' in section.configspec:
2392
many = spec_section['__many__']
2393
# dynamically assign the configspecs
2394
# for the sections below
2395
for entry in section.sections:
2396
self._handle_repeat(section[entry], many)
2401
for entry in spec_section:
2402
if entry == '__many__':
2404
if (not entry in section.scalars) or (entry in section.defaults):
2406
# or entries from defaults
2411
val = section[entry]
2138
check = validator.check(spec,
2413
check = validator.check(spec_section[entry],
2140
2415
missing=missing
2142
2417
except validator.baseErrorClass, e:
2143
if not preserve_errors or isinstance(e, self._vdtMissingValue):
2418
if not preserve_errors or isinstance(e, VdtMissingValue):
2144
2419
out[entry] = False
2146
2421
# preserve the error
2271
2462
elif ret_false:
2277
"""Clear ConfigObj instance and restore to 'freshly created' state."""
2280
# FIXME: Should be done by '_initialise', but ConfigObj constructor (and reload)
2281
# requires an empty dictionary
2282
self.configspec = None
2283
# Just to be sure ;-)
2284
self._original_configspec = None
2289
Reload a ConfigObj from file.
2291
This method raises a ``ReloadError`` if the ConfigObj doesn't have
2292
a filename attribute pointing to a file.
2294
if not isinstance(self.filename, basestring):
2297
filename = self.filename
2298
current_options = {}
2299
for entry in OPTION_DEFAULTS:
2300
if entry == 'configspec':
2302
current_options[entry] = getattr(self, entry)
2304
configspec = self._original_configspec
2305
current_options['configspec'] = configspec
2308
self._initialise(current_options)
2309
self._load(filename, configspec)
2313
2467
class SimpleVal(object):
2315
2469
A simple validator.
2316
2470
Can be used to check that all members expected are present.
2318
2472
To use it, provide a configspec with all your members in (the value given
2319
2473
will be ignored). Pass an instance of ``SimpleVal`` to the ``validate``
2320
2474
method of your ``ConfigObj``. ``validate`` will return ``True`` if all
2321
2475
members are present, or a dictionary with True/False meaning
2322
2476
present/missing. (Whole missing sections will be replaced with ``False``)
2478
>>> val = SimpleVal()
2494
... '''.split('\\n')
2495
>>> configspec = '''
2510
... '''.split('\\n')
2511
>>> o = ConfigObj(config, configspec=configspec)
2514
>>> o = ConfigObj(configspec=configspec)
2325
2519
def __init__(self):
2326
2520
self.baseErrorClass = ConfigObjError
2328
2522
def check(self, check, member, missing=False):
2329
2523
"""A dummy check method, always returns the value unchanged."""
2331
raise self.baseErrorClass()
2525
raise self.baseErrorClass
2335
2528
# Check / processing functions for options
2336
2529
def flatten_errors(cfg, res, levels=None, results=None):
2338
2531
An example function that will turn a nested dictionary of results
2339
2532
(as returned by ``ConfigObj.validate``) into a flat list.
2341
2534
``cfg`` is the ConfigObj instance being checked, ``res`` is the results
2342
2535
dictionary returned by ``validate``.
2344
2537
(This is a recursive function, so you shouldn't use the ``levels`` or
2345
``results`` arguments - they are used by the function.)
2538
``results`` arguments - they are used by the function.
2347
2540
Returns a list of keys that failed. Each member of the list is a tuple :
2351
2543
([list of sections...], key, result)
2353
2545
If ``validate`` was called with ``preserve_errors=False`` (the default)
2354
2546
then ``result`` will always be ``False``.
2356
2548
*list of sections* is a flattened list of sections that the key was found
2359
If the section was missing (or a section was expected and a scalar provided
2360
- or vice-versa) then key will be ``None``.
2551
If the section was missing then key will be ``None``.
2362
2553
If the value (or section) was missing then ``result`` will be ``False``.
2364
2555
If ``validate`` was called with ``preserve_errors=True`` and a value
2365
2556
was present, but failed the check, then ``result`` will be the exception
2366
2557
object returned. You can use this as a string that describes the failure.
2368
2559
For example *The value "3" is of the wrong type*.
2561
# FIXME: is the ordering of the output arbitrary ?
2370
2562
>>> import validate
2371
2563
>>> vtor = validate.Validator()
2372
2564
>>> my_ini = '''
2461
"""*A programming language is a medium of expression.* - Paul Graham"""
2653
# FIXME: test error code for badly built multiline values
2654
# FIXME: test handling of StringIO
2655
# FIXME: test interpolation with writing
2659
Dummy function to hold some of the doctests.
2696
... 'keys11': 'val1',
2697
... 'keys13': 'val3',
2698
... 'keys12': 'val2',
2701
... 'section 2 sub 1': {
2704
... 'keys21': 'val1',
2705
... 'keys22': 'val2',
2706
... 'keys23': 'val3',
2711
... 'a' = b # !"$%^&*(),::;'@~#= 33
2712
... "b" = b #= 6, 33
2713
... ''' .split('\\n')
2714
>>> t2 = ConfigObj(t)
2715
>>> assert t2 == {'a': 'b', 'b': 'b'}
2716
>>> t2.inline_comments['b'] = ''
2718
>>> assert t2.write() == ['','b = b', '']
2720
# Test ``list_values=False`` stuff
2722
... key1 = no quotes
2723
... key2 = 'single quotes'
2724
... key3 = "double quotes"
2725
... key4 = "list", 'with', several, "quotes"
2727
>>> cfg = ConfigObj(c.splitlines(), list_values=False)
2728
>>> cfg == {'key1': 'no quotes', 'key2': "'single quotes'",
2729
... 'key3': '"double quotes"',
2730
... 'key4': '"list", \\'with\\', several, "quotes"'
2733
>>> cfg = ConfigObj(list_values=False)
2734
>>> cfg['key1'] = 'Multiline\\nValue'
2735
>>> cfg['key2'] = '''"Value" with 'quotes' !'''
2737
["key1 = '''Multiline\\nValue'''", 'key2 = "Value" with \\'quotes\\' !']
2738
>>> cfg.list_values = True
2739
>>> cfg.write() == ["key1 = '''Multiline\\nValue'''",
2740
... 'key2 = \\'\\'\\'"Value" with \\'quotes\\' !\\'\\'\\'']
2743
Test flatten_errors:
2745
>>> from validate import Validator, VdtValueTooSmallError
2761
... '''.split('\\n')
2762
>>> configspec = '''
2763
... test1= integer(30,50)
2766
... test4=float(6.0)
2768
... test1=integer(30,50)
2771
... test4=float(6.0)
2773
... test1=integer(30,50)
2776
... test4=float(6.0)
2777
... '''.split('\\n')
2778
>>> val = Validator()
2779
>>> c1 = ConfigObj(config, configspec=configspec)
2780
>>> res = c1.validate(val)
2781
>>> flatten_errors(c1, res) == [([], 'test4', False), (['section',
2782
... 'sub section'], 'test4', False), (['section'], 'test4', False)]
2784
>>> res = c1.validate(val, preserve_errors=True)
2785
>>> check = flatten_errors(c1, res)
2789
(['section', 'sub section'], 'test4')
2791
(['section'], 'test4')
2792
>>> for entry in check:
2793
... isinstance(entry[2], VdtValueTooSmallError)
2794
... print str(entry[2])
2796
the value "5.0" is too small.
2798
the value "5.0" is too small.
2800
the value "5.0" is too small.
2802
Test unicode handling, BOM, write witha file like object and line endings :
2804
... # initial comment
2805
... # inital comment 2
2807
... test1 = some value
2809
... test2 = another value # inline comment
2810
... # section comment
2811
... [section] # inline comment
2812
... test = test # another inline comment
2816
... # final comment2
2818
>>> u = u_base.encode('utf_8').splitlines(True)
2819
>>> u[0] = BOM_UTF8 + u[0]
2820
>>> uc = ConfigObj(u)
2821
>>> uc.encoding = None
2824
>>> uc == {'test1': 'some value', 'test2': 'another value',
2825
... 'section': {'test': 'test', 'test2': 'test2'}}
2827
>>> uc = ConfigObj(u, encoding='utf_8', default_encoding='latin-1')
2830
>>> isinstance(uc['test1'], unicode)
2836
>>> uc['latin1'] = "This costs lot's of "
2837
>>> a_list = uc.write()
2840
>>> isinstance(a_list[0], str)
2842
>>> a_list[0].startswith(BOM_UTF8)
2844
>>> u = u_base.replace('\\n', '\\r\\n').encode('utf_8').splitlines(True)
2845
>>> uc = ConfigObj(u)
2848
>>> uc.newlines = '\\r'
2849
>>> from cStringIO import StringIO
2850
>>> file_like = StringIO()
2851
>>> uc.write(file_like)
2852
>>> file_like.seek(0)
2853
>>> uc2 = ConfigObj(file_like)
2856
>>> uc2.filename is None
2858
>>> uc2.newlines == '\\r'
2862
if __name__ == '__main__':
2863
# run the code tests in doctest format
2866
key1= val # comment 1
2867
key2= val # comment 2
2870
key1= val # comment 5
2871
key2= val # comment 6
2874
key1= val # comment 9
2875
key2= val # comment 10
2877
[[lev2ba]] # comment 12
2878
key1= val # comment 13
2880
[[lev2bb]] # comment 15
2881
key1= val # comment 16
2883
[lev1c] # comment 18
2885
[[lev2c]] # comment 20
2887
[[[lev3c]]] # comment 22
2888
key1 = val # comment 23"""
2894
["section 1"] # comment
2903
[['section 2 sub 1']]
2908
name1 = """ a single line value """ # comment
2909
name2 = \''' another single line value \''' # comment
2910
name3 = """ a single line value """
2911
name4 = \''' another single line value \'''
2928
\''' # I guess this is a comment too
2932
m = sys.modules.get('__main__')
2933
globs = m.__dict__.copy()
2934
a = ConfigObj(testconfig1.split('\n'), raise_errors=True)
2935
b = ConfigObj(testconfig2.split('\n'), raise_errors=True)
2936
i = ConfigObj(testconfig6.split('\n'), raise_errors=True)
2938
'INTP_VER': INTP_VER,
2943
doctest.testmod(m, globs=globs)
2954
Better support for configuration from multiple files, including tracking
2955
*where* the original file came from and writing changes to the correct
2959
Make ``newline`` an option (as well as an attribute) ?
2961
``UTF16`` encoded files, when returned as a list of lines, will have the
2962
BOM at the start of every line. Should this be removed from all but the
2965
Option to set warning type for unicode decode ? (Defaults to strict).
2967
A method to optionally remove uniform indentation from multiline values.
2968
(do as an example of using ``walk`` - along with string-escape)
2970
Should the results dictionary from validate be an ordered dictionary if
2971
`odict <http://www.voidspace.org.uk/python/odict.html>`_ is available ?
2973
Implement a better ``__repr__`` ? (``ConfigObj({})``)
2975
Implement some of the sequence methods (which include slicing) from the
2978
INCOMPATIBLE CHANGES
2979
====================
2981
(I have removed a lot of needless complications - this list is probably not
2982
conclusive, many option/attribute/method names have changed)
2986
The only valid divider is '='
2988
We've removed line continuations with '\'
2990
No recursive lists in values
2994
No distinction between flatfiles and non flatfiles
2996
Change in list syntax - use commas to indicate list, not parentheses
2997
(square brackets and parentheses are no longer recognised as lists)
2999
';' is no longer valid for comments and no multiline comments
3003
We don't allow empty values - have to use '' or ""
3005
In ConfigObj 3 - setting a non-flatfile member to ``None`` would
3006
initialise it as an empty section.
3008
The escape entities '&mjf-lf;' and '&mjf-quot;' have gone
3009
replaced by triple quote, multiple line values.
3011
The ``newline``, ``force_return``, and ``default`` options have gone
3013
The ``encoding`` and ``backup_encoding`` methods have gone - replaced
3014
with the ``encode`` and ``decode`` methods.
3016
``fileerror`` and ``createempty`` options have become ``file_error`` and
3019
Partial configspecs (for specifying the order members should be written
3020
out and which should be present) have gone. The configspec is no longer
3021
used to specify order for the ``write`` method.
3023
Exceeding the maximum depth of recursion in string interpolation now
3024
raises an error ``InterpolationDepthError``.
3026
Specifying a value for interpolation which doesn't exist now raises an
3027
error ``MissingInterpolationOption`` (instead of merely being ignored).
3029
The ``writein`` method has been removed.
3031
The comments attribute is now a list (``inline_comments`` equates to the
3032
old comments attribute)
3037
``validate`` doesn't report *extra* values or sections.
3039
You can't have a keyword with the same name as a section (in the same
3040
section). They are both dictionary keys - so they would overlap.
3042
ConfigObj doesn't quote and unquote values if ``list_values=False``.
3043
This means that leading or trailing whitespace in values will be lost when
3044
writing. (Unless you manually quote).
3046
Interpolation checks first the 'DEFAULT' subsection of the current
3047
section, next it checks the 'DEFAULT' section of the parent section,
3048
last it checks the 'DEFAULT' section of the main section.
3050
Logically a 'DEFAULT' section should apply to all subsections of the *same
3051
parent* - this means that checking the 'DEFAULT' subsection in the
3052
*current section* is not necessarily logical ?
3054
In order to simplify unicode support (which is possibly of limited value
3055
in a config file) I have removed automatic support and added the
3056
``encode`` and ``decode methods, which can be used to transform keys and
3057
entries. Because the regex looks for specific values on inital parsing
3058
(i.e. the quotes and the equals signs) it can only read ascii compatible
3059
encodings. For unicode use ``UTF8``, which is ASCII compatible.
3061
Does it matter that we don't support the ':' divider, which is supported
3062
by ``ConfigParser`` ?
3064
The regular expression correctly removes the value -
3065
``"'hello', 'goodbye'"`` and then unquote just removes the front and
3066
back quotes (called from ``_handle_value``). What should we do ??
3067
(*ought* to raise exception because it's an invalid value if lists are
3068
off *sigh*. This is not what you want if you want to do your own list
3069
processing - would be *better* in this case not to unquote.)
3071
String interpolation and validation don't play well together. When
3072
validation changes type it sets the value. This will correctly fetch the
3073
value using interpolation - but then overwrite the interpolation reference.
3074
If the value is unchanged by validation (it's a string) - but other types
3081
List values allow you to specify multiple values for a keyword. This
3082
maps to a list as the resulting Python object when parsed.
3084
The syntax for lists is easy. A list is a comma separated set of values.
3085
If these values contain quotes, the hash mark, or commas, then the values
3086
can be surrounded by quotes. e.g. : ::
3088
keyword = value1, 'value 2', "value 3"
3090
If a value needs to be a list, but only has one member, then you indicate
3091
this with a trailing comma. e.g. : ::
3093
keyword = "single value",
3095
If a value needs to be a list, but it has no members, then you indicate
3096
this with a single comma. e.g. : ::
3098
keyword = , # an empty list
3100
Using triple quotes it will be possible for single values to contain
3101
newlines and *both* single quotes and double quotes. Triple quotes aren't
3102
allowed in list values. This means that the members of list values can't
3103
contain carriage returns (or line feeds :-) or both quote values.
3111
Removed ``BOM_UTF8`` from ``__all__``.
3113
The ``BOM`` attribute has become a boolean. (Defaults to ``False``.) It is
3114
*only* ``True`` for the ``UTF16`` encoding.
3116
File like objects no longer need a ``seek`` attribute.
3118
ConfigObj no longer keeps a reference to file like objects. Instead the
3119
``write`` method takes a file like object as an optional argument. (Which
3120
will be used in preference of the ``filename`` attribute if htat exists as
3123
Full unicode support added. New options/attributes ``encoding``,
3124
``default_encoding``.
3126
utf16 files decoded to unicode.
3128
If ``BOM`` is ``True``, but no encoding specified, then the utf8 BOM is
3129
written out at the start of the file. (It will normally only be ``True`` if
3130
the utf8 BOM was found when the file was read.)
3132
File paths are *not* converted to absolute paths, relative paths will
3133
remain relative as the ``filename`` attribute.
3135
Fixed bug where ``final_comment`` wasn't returned if ``write`` is returning
3141
Added ``True``, ``False``, and ``enumerate`` if they are not defined.
3142
(``True`` and ``False`` are needed for *early* versions of Python 2.2,
3143
``enumerate`` is needed for all versions ofPython 2.2)
3145
Deprecated ``istrue``, replaced it with ``as_bool``.
3147
Added ``as_int`` and ``as_float``.
3149
utf8 and utf16 BOM handled in an endian agnostic way.
3154
Validation no longer done on the 'DEFAULT' section (only in the root
3155
level). This allows interpolation in configspecs.
3157
Change in validation syntax implemented in validate 0.2.1
3164
Added ``merge``, a recursive update.
3166
Added ``preserve_errors`` to ``validate`` and the ``flatten_errors``
3169
Thanks to Matthew Brett for suggestions and helping me iron out bugs.
3171
Fixed bug where a config file is *all* comment, the comment will now be
3172
``initial_comment`` rather than ``final_comment``.
3177
Fixed bug in ``create_empty``. Thanks to Paul Jimenez for the report.
3182
Fixed bug in ``Section.walk`` when transforming names as well as values.
3184
Added the ``istrue`` method. (Fetches the boolean equivalent of a string
3187
Fixed ``list_values=False`` - they are now only quoted/unquoted if they
3188
are multiline values.
3190
List values are written as ``item, item`` rather than ``item,item``.
3197
Fixed typo in ``write`` method. (Testing for the wrong value when resetting
3205
Fixed bug in ``setdefault`` - creating a new section *wouldn't* return
3206
a reference to the new section.
3211
Removed ``PositionError``.
3213
Allowed quotes around keys as documented.
3215
Fixed bug with commas in comments. (matched as a list value)
3222
Fixed bug in initialising ConfigObj from a ConfigObj.
3224
Changed the mailing list address.
3231
Fixed bug in ``Section.__delitem__`` oops.
3236
Interpolation is switched off before writing out files.
3238
Fixed bug in handling ``StringIO`` instances. (Thanks to report from
3239
"Gustavo Niemeyer" <gustavo@niemeyer.net>)
3241
Moved the doctests from the ``__init__`` method to a separate function.
3242
(For the sake of IDE calltips).
3249
String values unchanged by validation *aren't* reset. This preserves
3250
interpolation in string values.
3255
None from a default is turned to '' if stringify is off - because setting
3256
a value to None raises an error.
3265
Actually added the RepeatSectionError class ;-)
3270
If ``stringify`` is off - list values are preserved by the ``validate``
3278
Fixed ``simpleVal``.
3280
Added ``RepeatSectionError`` error if you have additional sections in a
3281
section with a ``__many__`` (repeated) section.
3285
Reworked the ConfigObj._parse, _handle_error and _multiline methods:
3286
mutated the self._infile, self._index and self._maxline attributes into
3287
local variables and method parameters
3289
Reshaped the ConfigObj._multiline method to better reflect its semantics
3291
Changed the "default_test" test in ConfigObj.validate to check the fix for
3292
the bug in validate.Validator.check
3299
Updated comments at top
3306
Implemented repeated sections.
3310
Added test for interpreter version: raises RuntimeError if earlier than
3318
Implemented default values in configspecs.
3322
Fixed naked except: clause in validate that was silencing the fact
3323
that Python2.2 does not have dict.pop
3330
Bug fix causing error if file didn't exist.
3337
Adjusted doctests for Python 2.2.3 compatibility
3344
Added the inline_comments attribute
3346
We now preserve and rewrite all comments in the config file
3348
configspec is now a section attribute
3350
The validate method changes values in place
3352
Added InterpolationError
3354
The errors now have line number, line, and message attributes. This
3355
simplifies error handling
3364
Fixed bug in Section.pop (now doesn't raise KeyError if a default value
3367
Replaced ``basestring`` with ``types.StringTypes``
3369
Removed the ``writein`` method
3378
Indentation in config file is not significant anymore, subsections are
3379
designated by repeating square brackets
3381
Adapted all tests and docs to the new format
3395
Reformatted final docstring in ReST format, indented it for easier folding
3397
Code tests converted to doctest format, and scattered them around
3398
in various docstrings
3400
Walk method rewritten using scalars and sections attributes
3407
Changed Validator and SimpleVal "test" methods to "check"
3414
Changed Section.sequence to Section.scalars and Section.sections
3416
Added Section.configspec
3418
Sections in the root section now have no extra indentation
3420
Comments now better supported in Section and preserved by ConfigObj
3422
Comments also written out
3424
Implemented initial_comment and final_comment
3426
A scalar value after a section will now raise an error
3431
Fixed a couple of bugs
3433
Can now pass a tuple instead of a list
3435
Simplified dict and walk methods
3437
Added __str__ to Section
3449
The stringify option implemented. On by default.
3454
Renamed private attributes with a single underscore prefix.
3456
Changes to interpolation - exceeding recursion depth, or specifying a
3457
missing value, now raise errors.
3459
Changes for Python 2.2 compatibility. (changed boolean tests - removed
3460
``is True`` and ``is False``)
3462
Added test for duplicate section and member (and fixed bug)
3476
Now properly handles values including comments and lists.
3478
Better error handling.
3480
String interpolation.
3482
Some options implemented.
3484
You can pass a Section a dictionary to initialise it.
3486
Setting a Section member to a dictionary will create a Section instance.
3493
Experimental reader.
3495
A reasonably elegant implementation - a basic reader in 160 lines of code.
3497
*A programming language is a medium of expression.* - Paul Graham