149
161
'indent_type': None,
150
162
'encoding': None,
151
163
'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))
154
248
class ConfigObjError(SyntaxError):
156
250
This is the base class for all errors that ConfigObj raises.
157
251
It is a subclass of SyntaxError.
159
>>> raise ConfigObjError
160
Traceback (most recent call last):
163
253
def __init__(self, message='', line_number=None, line=''):
165
255
self.line_number = line_number
166
self.message = message
167
256
SyntaxError.__init__(self, message)
169
259
class NestingError(ConfigObjError):
171
261
This error indicates a level of nesting that doesn't match.
173
>>> raise NestingError
174
Traceback (most recent call last):
178
265
class ParseError(ConfigObjError):
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.
185
Traceback (most recent call last):
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.')
189
282
class DuplicateError(ConfigObjError):
191
284
The keyword or section specified already exists.
193
>>> raise DuplicateError
194
Traceback (most recent call last):
198
288
class ConfigspecError(ConfigObjError):
200
290
An error occured whilst parsing a configspec.
202
>>> raise ConfigspecError
203
Traceback (most recent call last):
207
294
class InterpolationError(ConfigObjError):
208
295
"""Base class for the two interpolation errors."""
210
class InterpolationDepthError(InterpolationError):
298
class InterpolationLoopError(InterpolationError):
211
299
"""Maximum interpolation depth exceeded in string interpolation."""
213
301
def __init__(self, option):
215
>>> raise InterpolationDepthError('yoda')
216
Traceback (most recent call last):
217
InterpolationDepthError: max interpolation depth exceeded in value "yoda".
219
302
InterpolationError.__init__(
221
'max interpolation depth exceeded in value "%s".' % option)
304
'interpolation loop detected in value "%s".' % option)
223
307
class RepeatSectionError(ConfigObjError):
225
309
This error indicates additional sections in a section with a
226
310
``__many__`` (repeated) section.
228
>>> raise RepeatSectionError
229
Traceback (most recent call last):
233
314
class MissingInterpolationOption(InterpolationError):
234
315
"""A value specified for interpolation was missing."""
236
317
def __init__(self, option):
238
>>> raise MissingInterpolationOption('yoda')
239
Traceback (most recent call last):
240
MissingInterpolationOption: missing option "yoda" in interpolation.
242
318
InterpolationError.__init__(
244
320
'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)
246
493
class Section(dict):
248
495
A dictionary-like object that represents a section in a config file.
250
It does string interpolation if the 'interpolate' attribute
497
It does string interpolation if the 'interpolation' attribute
251
498
of the 'main' object is set to True.
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.
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.
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.
260
508
Iteration follows the order: scalars, then sections.
263
_KEYCRE = re.compile(r"%\(([^)]*)\)s|.")
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)
265
521
def __init__(self, parent, depth, main, indict=None, name=None):
279
535
# level of nesting depth of this Section
280
536
self.depth = depth
537
# 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):
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
287
552
# for comments :-)
288
553
self.comments = {}
289
554
self.inline_comments = {}
556
self.configspec = None
293
558
self.defaults = []
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)
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
311
raise InterpolationDepthError(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)
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)
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)
342
def __setitem__(self, key, value):
593
def __setitem__(self, key, value, unrepr=False):
344
595
Correctly set a value.
346
597
Making dictionary values Section instances.
347
598
(We have to special case 'Section' instances - which are also dicts)
349
600
Keys must be strings.
350
601
Values need only be strings (or lists of strings) if
351
602
``main.stringify`` is set.
604
``unrepr`` must be set when setting a value to a dictionary, without
605
creating a new sub-section.
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)
355
610
# add the comment
356
611
if key not in self.comments:
357
612
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
... 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.'
689
>>> m.encode('ascii')
693
def decode(section, key, encoding=encoding):
696
if isinstance(val, (list, tuple)):
699
newval.append(entry.decode(encoding))
700
elif isinstance(val, dict):
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)
710
def encode(self, encoding):
712
Encode all strings and values from unicode,
713
using the specified encoding.
715
Works with subsections and list values.
716
Uses the ``walk`` method.
718
def encode(section, key, encoding=encoding):
721
if isinstance(val, (list, tuple)):
724
newval.append(entry.encode(encoding))
725
elif isinstance(val, dict):
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)
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)
740
947
def as_bool(self, key):
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.
746
If the string is one of ``True``, ``On``, ``Yes``, or ``1`` it returns
953
If the string is one of ``True``, ``On``, ``Yes``, or ``1`` it returns
749
If the string is one of ``False``, ``Off``, ``No``, or ``0`` it returns
956
If the string is one of ``False``, ``Off``, ``No``, or ``0`` it returns
752
959
``as_bool`` is not case sensitive.
754
961
Any other input will raise a ``ValueError``.
756
963
>>> a = ConfigObj()
757
964
>>> a['a'] = 'fish'
758
965
>>> a.as_bool('a')
951
1190
'true': True, 'false': False,
954
def __init__(self, infile=None, options=None, **kwargs):
1194
def __init__(self, infile=None, options=None, _inspec=False, **kwargs):
956
Parse or create a config file object.
1196
Parse a config file or create a config file object.
958
1198
``ConfigObj(infile=None, options=None, **kwargs)``
1200
self._inspec = _inspec
1201
# init the superclass
1202
Section.__init__(self, self, 0, self)
1204
infile = infile or []
1205
options = dict(options or {})
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)
1210
options['list_values'] = False
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.
1214
for entry in options:
1215
if entry not in defaults:
1216
raise TypeError('Unrecognised option "%s".' % entry)
975
1218
# Add any explicit options to the defaults
976
1219
defaults.update(options)
978
# initialise a few variables
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']
993
self.initial_comment = []
994
self.final_comment = []
996
if isinstance(infile, StringTypes):
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):
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 []
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)
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')
1012
1246
elif isinstance(infile, (list, tuple)):
1013
1247
infile = list(infile)
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()
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'])
1260
if configspec is not None:
1261
self._handle_configspec(configspec)
1026
1263
self.configspec = None
1028
elif getattr(infile, 'read', None) is not None:
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
1034
raise TypeError, ('infile must be a filename,'
1035
' file like object, or list of lines.')
1272
raise TypeError('infile must be a filename, file like object, or list of lines.')
1038
1275
# don't do it for the empty ConfigObj
1039
1276
infile = self._handle_bom(infile)
1385
1605
'Parse error in value at line %s.',
1386
1606
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,
1389
# extract comment and lists
1391
(value, comment) = self._handle_value(value)
1394
'Parse error in value at line %s.',
1395
ParseError, infile, cur_index)
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)
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)
1407
## sys.stderr.write(this_section.name + '\n')
1408
this_section[key] = value
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')
1419
# it neither matched as a keyword
1420
# or a section marker
1422
'Invalid line at line "%s".',
1423
ParseError, infile, cur_index)
1424
1658
if self.indent_type is None:
1425
1659
# no indentation used, set the type accordingly
1426
1660
self.indent_type = ''
1427
1662
# preserve the final comment
1428
1663
if not self and not self.initial_comment:
1429
1664
self.initial_comment = comment_list
1665
elif not reset_comment:
1431
1666
self.final_comment = comment_list
1667
self.list_values = temp_list_values
1433
1670
def _match_depth(self, sect, depth):
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.
1438
1675
Return a reference to the right section,
1439
1676
or raise a SyntaxError.
1441
1678
while depth < sect.depth:
1442
1679
if sect is sect.parent:
1443
1680
# we've reached the top level already
1445
1682
sect = sect.parent
1446
1683
if sect.depth == depth:
1448
1685
# shouldn't get here
1451
1689
def _handle_error(self, text, ErrorClass, infile, cur_index):
1453
1691
Handle an error according to the error settings.
1455
1693
Either raise the error or store it.
1456
1694
The error will have occured at ``cur_index``
1466
1704
# reraise when parsing has finished
1467
1705
self._errors.append(error)
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]
1475
1715
def _quote(self, value, multiline=True):
1477
1717
Return a safely quoted version of a value.
1479
1719
Raise a ConfigObjError if the value cannot be safely quoted.
1480
1720
If multiline is ``True`` (default) then use triple quotes
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.
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.
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 '#'.
1731
If ``write_empty_values`` is set, and the value is an empty string, it
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
1739
if multiline and isinstance(value, (list, tuple)):
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)
1502
raise TypeError, 'Value "%s" is not a string.' % value
1506
wspace_plus = ' \r\t\n\v\t\'"'
1750
raise TypeError('Value "%s" is not a string.' % value)
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))):
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:
1513
1761
if not self.list_values:
1514
1762
# we don't quote if ``list_values=False``
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.' %
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)):
1526
if ("'" in value) and ('"' in value):
1527
raise ConfigObjError, (
1528
'Value "%s" cannot be safely quoted.' % value)
1773
quot = self._get_single_quote(value)
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:
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)
1542
1781
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
if value.find('"""') == -1:
1544
1804
def _handle_value(self, value):
1546
1806
Given a value string, unquote, remove comment,
1547
1807
handle lists. (including empty and single member lists)
1549
Testing list values.
1551
>>> testconfig3 = '''
1554
... c = test1, test2 , test3
1555
... d = test1, test2, test3,
1557
>>> d = ConfigObj(testconfig3.split('\\n'), raise_errors=True)
1560
>>> d['b'] == ['test']
1562
>>> d['c'] == ['test1', 'test2', 'test3']
1564
>>> d['d'] == ['test1', 'test2', 'test3']
1567
Testing with list values off.
1570
... testconfig3.split('\\n'),
1571
... raise_errors=True,
1572
... list_values=False)
1575
>>> e['b'] == 'test,'
1577
>>> e['c'] == 'test1, test2 , test3'
1579
>>> e['d'] == 'test1, test2, test3,'
1582
Testing creating from a dictionary.
1605
>>> g = ConfigObj(f)
1609
Testing we correctly detect badly built list values (4 of them).
1611
>>> testconfig4 = '''
1615
... dummy = ,,hello, goodbye
1618
... ConfigObj(testconfig4.split('\\n'))
1619
... except ConfigObjError, e:
1623
Testing we correctly detect badly quoted values (4 of them).
1625
>>> testconfig5 = '''
1626
... config = "hello # comment
1628
... fish = 'goodbye # comment
1629
... dummy = "hello again
1632
... ConfigObj(testconfig5.split('\\n'))
1633
... except ConfigObjError, e:
1810
# Parsing a configspec so don't handle comments
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:
1642
(value, comment) = mat.groups()
1643
1817
# NOTE: we don't unquote here
1644
return (value, comment)
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
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
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
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)
1717
1878
# we've got to the end of the config, oops...
1719
1880
mat = multi_line.match(line)
1720
1881
if mat is None:
1721
1882
# a badly formed line
1723
1884
(value, comment) = mat.groups()
1724
1885
return (newvalue + value, comment, cur_index)
1726
1888
def _handle_configspec(self, configspec):
1727
1889
"""Parse the configspec."""
1729
configspec = ConfigObj(
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)
1739
raise IOError('Reading configspec failed: %s' % e)
1740
self._set_configspec_value(configspec, self)
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):
1894
configspec = ConfigObj(configspec,
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)
1903
raise IOError('Reading configspec failed: %s' % e)
1905
self.configspec = configspec
1909
def _set_configspec(self, section, copy):
1911
Called by validate. Handles setting the configspec on subsections
1912
including sections to be validated by __many__
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
1751
1921
for entry in configspec.sections:
1752
1922
if entry == '__many__':
1754
1924
if entry not in section:
1755
1925
section[entry] = {}
1756
self._set_configspec_value(configspec[entry], section[entry])
1758
def _handle_repeat(self, section, configspec):
1759
"""Dynamically assign configspec for repeated section."""
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
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
1781
sections[entry] = val
1783
section.configspec = scalars
1784
for entry in sections:
1785
if entry not in section:
1787
self._handle_repeat(section[entry], sections[entry])
1928
section.comments[entry] = configspec.comments.get(entry, [])
1929
section.inline_comments[entry] = configspec.inline_comments.get(entry, '')
1931
# Could be a scalar when we expect a section
1932
if isinstance(section[entry], Section):
1933
section[entry].configspec = configspec[entry]
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' % (
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))
1940
val = self._decode_element(self._quote(this_entry))
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(' = '),
1947
self._decode_element(comment))
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' % (
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))
1808
1959
def _handle_comment(self, comment):
1810
Deal with a comment.
1812
>>> filename = a.filename
1813
>>> a.filename = None
1814
>>> values = a.write()
1816
>>> while index < 23:
1818
... line = values[index-1]
1819
... assert line.endswith('# comment ' + str(index))
1820
>>> a.filename = filename
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
1832
>>> nc.final_comment == end_comment
1960
"""Deal with a comment."""
1835
1961
if not comment:
1837
if self.indent_type == '\t':
1838
start = self._a_to_u('\t')
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)
1845
def _compute_indent_string(self, depth):
1847
Compute the indent string, according to current indent_type and depth
1849
if self.indent_type == '':
1850
# no indentation at all
1852
if self.indent_type == '\t':
1854
if self.indent_type == ' ':
1855
return ' ' * NUM_INDENT_SPACES * depth
1858
1969
# Public methods
1860
1971
def write(self, outfile=None, section=None):
1862
1973
Write the current ConfigObj as a file
1864
1975
tekNico: FIXME: use StringIO instead of real files
1866
1977
>>> filename = a.filename
1867
1978
>>> a.filename = 'test.ini'
1869
1980
>>> a.filename = filename
1870
1981
>>> a == ConfigObj('test.ini', raise_errors=True)
1872
>>> os.remove('test.ini')
1873
>>> b.filename = 'test.ini'
1875
>>> b == ConfigObj('test.ini', raise_errors=True)
1877
>>> os.remove('test.ini')
1878
>>> i.filename = 'test.ini'
1880
>>> i == ConfigObj('test.ini', raise_errors=True)
1882
>>> os.remove('test.ini')
1884
>>> a['DEFAULT'] = {'a' : 'fish'}
1885
>>> a['a'] = '%(a)s'
1887
['a = %(a)s', '[DEFAULT]', 'a = fish']
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
1894
1989
cs = self._a_to_u('#')
1895
1990
csp = self._a_to_u('# ')
1959
2053
out[0] = BOM_UTF8 + out[0]
1962
2056
# Turn the list to a string, joined with correct newlines
1963
output = (self._a_to_u(self.newlines or os.linesep)
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
2065
if not output.endswith(newline):
1971
2067
if outfile is not None:
1972
2068
outfile.write(output)
1974
h = open(self.filename, 'w')
2070
h = open(self.filename, 'wb')
1975
2071
h.write(output)
1978
def validate(self, validator, preserve_errors=False, section=None):
2075
def validate(self, validator, preserve_errors=False, copy=False,
1980
2078
Test the ConfigObj against a configspec.
1982
2080
It uses the ``validator`` object from *validate.py*.
1984
2082
To run ``validate`` on the current ConfigObj, call: ::
1986
2084
test = config.validate(validator)
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).
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
1997
2095
In addition, it converts the values from strings to their native
1998
2096
types if their checks pass (and ``stringify`` is set).
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``.
2007
2105
You must have the validate module to use ``preserve_errors=True``.
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.
2014
... from validate import Validator
2015
... except ImportError:
2016
... sys.stderr.write('Cannot import the Validator object, skipping the related tests\n')
2033
... '''.split('\\n')
2034
... configspec = '''
2035
... test1= integer(30,50)
2038
... test4=float(6.0)
2040
... test1=integer(30,50)
2043
... test4=float(6.0)
2045
... test1=integer(30,50)
2048
... test4=float(6.0)
2049
... '''.split('\\n')
2050
... val = Validator()
2051
... c1 = ConfigObj(config, configspec=configspec)
2052
... test = c1.validate(val)
2063
... 'sub section': {
2072
>>> val.check(c1.configspec['test4'], c1['test4'])
2073
Traceback (most recent call last):
2074
VdtValueTooSmallError: the value "5.0" is too small.
2076
>>> val_test_config = '''
2081
... key2 = 1.1, 3.0, 17, 6.8
2084
... key2 = True'''.split('\\n')
2085
>>> val_test_configspec = '''
2090
... key2 = float_list(4)
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)
2097
>>> val_test['key'] = 'text not a digit'
2098
>>> val_res = val_test.validate(val)
2099
>>> val_res == {'key2': True, 'section': True, 'key': False}
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)
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)
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)
2119
{'test1': '30', 'section': {'sub section': {}}}
2120
>>> default_test.validate(val)
2122
>>> default_test == {
2124
... 'test2': 'hello',
2129
... 'test2': 'hello',
2132
... 'sub section': {
2135
... 'test2': 'hello',
2142
Now testing with repeated sections : BIG TEST
2144
>>> repeated_1 = '''
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)
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 = '''
2165
... # blank dogs with puppies
2166
... # should be filled in by the configspec
2181
... # blank cats with kittens
2182
... # should be filled in by the configspec
2195
... '''.split('\\n')
2196
>>> repeated_3 = '''
2207
... '''.split('\\n')
2208
>>> repeated_4 = '''
2211
... name = string(default=Michael)
2212
... age = float(default=0.0)
2213
... sex = option(m, f, default=m)
2214
... '''.split('\\n')
2215
>>> repeated_5 = '''
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)
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)
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},
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},
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},
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},
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},
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},
2288
>>> repeater = ConfigObj(repeated_3, configspec=repeated_1)
2289
>>> repeater.validate(val)
2293
... 'cat1': {'fleas': True, 'tail': 'short', 'name': 'pussy'},
2294
... 'cat2': {'fleas': True, 'tail': 'short', 'name': 'pussy'},
2295
... 'cat3': {'fleas': True, 'tail': 'short', 'name': 'pussy'},
2298
... 'dog1': {'fleas': True, 'tail': 'long', 'name': 'rover'},
2299
... 'dog2': {'fleas': True, 'tail': 'long', 'name': 'rover'},
2300
... 'dog3': {'fleas': True, 'tail': 'long', 'name': 'rover'},
2304
>>> repeater = ConfigObj(configspec=repeated_4)
2305
>>> repeater['Michael'] = {}
2306
>>> repeater.validate(val)
2309
... 'Michael': {'age': 0.0, 'name': 'Michael', 'sex': 'm'},
2312
>>> repeater = ConfigObj(repeated_3, configspec=repeated_5)
2314
... 'dogs': {'dog1': {}, 'dog2': {}, 'dog3': {}},
2315
... 'cats': {'cat1': {}, 'cat2': {}, 'cat3': {}},
2318
>>> repeater.validate(val)
2321
... 'dogs': {'dog1': {}, 'dog2': {}, 'dog3': {}},
2325
... 'tail': 'short',
2326
... 'name': 'pussy',
2327
... 'description': {
2329
... 'height': 3.2999999999999998,
2330
... 'coat': {'fur': 'black', 'condition': 5},
2335
... 'tail': 'short',
2336
... 'name': 'pussy',
2337
... 'description': {
2339
... 'height': 3.2999999999999998,
2340
... 'coat': {'fur': 'black', 'condition': 5},
2345
... 'tail': 'short',
2346
... 'name': 'pussy',
2347
... 'description': {
2349
... 'height': 3.2999999999999998,
2350
... 'coat': {'fur': 'black', 'condition': 5},
2357
Test that interpolation is preserved for validated string values.
2358
Also check that interpolation works in configspecs.
2360
>>> t['DEFAULT'] = {}
2361
>>> t['DEFAULT']['test'] = 'a'
2362
>>> t['test'] = '%(test)s'
2366
>>> t.configspec = {'test': 'string'}
2369
>>> t.interpolation = False
2371
{'test': '%(test)s', 'DEFAULT': {'test': 'a'}}
2373
... 'interpolated string = string(default="fuzzy-%(man)s")',
2377
>>> c = ConfigObj(configspec=specs)
2380
>>> c['interpolated string']
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
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
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)
2406
for entry in spec_section:
2407
if entry == '__many__':
2409
if (not entry in section.scalars) or (entry in section.defaults):
2411
# or entries from defaults
2416
val = section[entry]
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
2131
configspec = section.configspec
2132
self._set_configspec(section, copy)
2134
def validate_entry(entry, spec, val, missing, ret_true, ret_false):
2418
check = validator.check(spec_section[entry],
2136
check = validator.check(spec,
2420
2138
missing=missing
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
2426
2144
# preserve the error
2467
2269
elif ret_false:
2275
"""Clear ConfigObj instance and restore to 'freshly created' state."""
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
2287
Reload a ConfigObj from file.
2289
This method raises a ``ReloadError`` if the ConfigObj doesn't have
2290
a filename attribute pointing to a file.
2292
if not isinstance(self.filename, basestring):
2295
filename = self.filename
2296
current_options = {}
2297
for entry in OPTION_DEFAULTS:
2298
if entry == 'configspec':
2300
current_options[entry] = getattr(self, entry)
2302
configspec = self._original_configspec
2303
current_options['configspec'] = configspec
2306
self._initialise(current_options)
2307
self._load(filename, configspec)
2472
2311
class SimpleVal(object):
2474
2313
A simple validator.
2475
2314
Can be used to check that all members expected are present.
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``)
2483
>>> val = SimpleVal()
2499
... '''.split('\\n')
2500
>>> configspec = '''
2515
... '''.split('\\n')
2516
>>> o = ConfigObj(config, configspec=configspec)
2519
>>> o = ConfigObj(configspec=configspec)
2524
2323
def __init__(self):
2525
2324
self.baseErrorClass = ConfigObjError
2527
2326
def check(self, check, member, missing=False):
2528
2327
"""A dummy check method, always returns the value unchanged."""
2530
raise self.baseErrorClass
2329
raise self.baseErrorClass()
2533
2333
# Check / processing functions for options
2534
2334
def flatten_errors(cfg, res, levels=None, results=None):
2536
2336
An example function that will turn a nested dictionary of results
2537
2337
(as returned by ``ConfigObj.validate``) into a flat list.
2539
2339
``cfg`` is the ConfigObj instance being checked, ``res`` is the results
2540
2340
dictionary returned by ``validate``.
2542
2342
(This is a recursive function, so you shouldn't use the ``levels`` or
2543
``results`` arguments - they are used by the function.
2343
``results`` arguments - they are used by the function.)
2545
2345
Returns a list of keys that failed. Each member of the list is a tuple :
2548
2349
([list of sections...], key, result)
2550
2351
If ``validate`` was called with ``preserve_errors=False`` (the default)
2551
2352
then ``result`` will always be ``False``.
2553
2354
*list of sections* is a flattened list of sections that the key was found
2556
If the section was missing then key will be ``None``.
2357
If the section was missing (or a section was expected and a scalar provided
2358
- or vice-versa) then key will be ``None``.
2558
2360
If the value (or section) was missing then ``result`` will be ``False``.
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.
2564
2366
For example *The value "3" is of the wrong type*.
2566
# FIXME: is the ordering of the output arbitrary ?
2567
2368
>>> import validate
2568
2369
>>> vtor = validate.Validator()
2569
2370
>>> my_ini = '''
2658
# FIXME: test error code for badly built multiline values
2659
# FIXME: test handling of StringIO
2660
# FIXME: test interpolation with writing
2664
Dummy function to hold some of the doctests.
2701
... 'keys11': 'val1',
2702
... 'keys13': 'val3',
2703
... 'keys12': 'val2',
2706
... 'section 2 sub 1': {
2709
... 'keys21': 'val1',
2710
... 'keys22': 'val2',
2711
... 'keys23': 'val3',
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'] = ''
2723
>>> assert t2.write() == ['','b = b', '']
2725
# Test ``list_values=False`` stuff
2727
... key1 = no quotes
2728
... key2 = 'single quotes'
2729
... key3 = "double quotes"
2730
... key4 = "list", 'with', several, "quotes"
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"'
2738
>>> cfg = ConfigObj(list_values=False)
2739
>>> cfg['key1'] = 'Multiline\\nValue'
2740
>>> cfg['key2'] = '''"Value" with 'quotes' !'''
2742
["key1 = '''Multiline\\nValue'''", 'key2 = "Value" with \\'quotes\\' !']
2743
>>> cfg.list_values = True
2744
>>> cfg.write() == ["key1 = '''Multiline\\nValue'''",
2745
... 'key2 = \\'\\'\\'"Value" with \\'quotes\\' !\\'\\'\\'']
2748
Test flatten_errors:
2750
>>> from validate import Validator, VdtValueTooSmallError
2766
... '''.split('\\n')
2767
>>> configspec = '''
2768
... test1= integer(30,50)
2771
... test4=float(6.0)
2773
... test1=integer(30,50)
2776
... test4=float(6.0)
2778
... test1=integer(30,50)
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)]
2789
>>> res = c1.validate(val, preserve_errors=True)
2790
>>> check = flatten_errors(c1, res)
2794
(['section', 'sub section'], 'test4')
2796
(['section'], 'test4')
2797
>>> for entry in check:
2798
... isinstance(entry[2], VdtValueTooSmallError)
2799
... print str(entry[2])
2801
the value "5.0" is too small.
2803
the value "5.0" is too small.
2805
the value "5.0" is too small.
2807
Test unicode handling, BOM, write witha file like object and line endings :
2809
... # initial comment
2810
... # inital comment 2
2812
... test1 = some value
2814
... test2 = another value # inline comment
2815
... # section comment
2816
... [section] # inline comment
2817
... test = test # another inline comment
2821
... # final comment2
2823
>>> u = u_base.encode('utf_8').splitlines(True)
2824
>>> u[0] = BOM_UTF8 + u[0]
2825
>>> uc = ConfigObj(u)
2826
>>> uc.encoding = None
2829
>>> uc == {'test1': 'some value', 'test2': 'another value',
2830
... 'section': {'test': 'test', 'test2': 'test2'}}
2832
>>> uc = ConfigObj(u, encoding='utf_8', default_encoding='latin-1')
2835
>>> isinstance(uc['test1'], unicode)
2841
>>> uc['latin1'] = "This costs lot's of "
2842
>>> a_list = uc.write()
2845
>>> isinstance(a_list[0], str)
2847
>>> a_list[0].startswith(BOM_UTF8)
2849
>>> u = u_base.replace('\\n', '\\r\\n').encode('utf_8').splitlines(True)
2850
>>> uc = ConfigObj(u)
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)
2861
>>> uc2.filename is None
2863
>>> uc2.newlines == '\\r'
2867
if __name__ == '__main__':
2868
# run the code tests in doctest format
2871
key1= val # comment 1
2872
key2= val # comment 2
2875
key1= val # comment 5
2876
key2= val # comment 6
2879
key1= val # comment 9
2880
key2= val # comment 10
2882
[[lev2ba]] # comment 12
2883
key1= val # comment 13
2885
[[lev2bb]] # comment 15
2886
key1= val # comment 16
2888
[lev1c] # comment 18
2890
[[lev2c]] # comment 20
2892
[[[lev3c]]] # comment 22
2893
key1 = val # comment 23"""
2899
["section 1"] # comment
2908
[['section 2 sub 1']]
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 \'''
2933
\''' # I guess this is a comment too
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)
2943
'INTP_VER': INTP_VER,
2948
doctest.testmod(m, globs=globs)
2959
Better support for configuration from multiple files, including tracking
2960
*where* the original file came from and writing changes to the correct
2964
Make ``newline`` an option (as well as an attribute) ?
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
2970
Option to set warning type for unicode decode ? (Defaults to strict).
2972
A method to optionally remove uniform indentation from multiline values.
2973
(do as an example of using ``walk`` - along with string-escape)
2975
Should the results dictionary from validate be an ordered dictionary if
2976
`odict <http://www.voidspace.org.uk/python/odict.html>`_ is available ?
2978
Implement a better ``__repr__`` ? (``ConfigObj({})``)
2980
Implement some of the sequence methods (which include slicing) from the
2983
INCOMPATIBLE CHANGES
2984
====================
2986
(I have removed a lot of needless complications - this list is probably not
2987
conclusive, many option/attribute/method names have changed)
2991
The only valid divider is '='
2993
We've removed line continuations with '\'
2995
No recursive lists in values
2999
No distinction between flatfiles and non flatfiles
3001
Change in list syntax - use commas to indicate list, not parentheses
3002
(square brackets and parentheses are no longer recognised as lists)
3004
';' is no longer valid for comments and no multiline comments
3008
We don't allow empty values - have to use '' or ""
3010
In ConfigObj 3 - setting a non-flatfile member to ``None`` would
3011
initialise it as an empty section.
3013
The escape entities '&mjf-lf;' and '&mjf-quot;' have gone
3014
replaced by triple quote, multiple line values.
3016
The ``newline``, ``force_return``, and ``default`` options have gone
3018
The ``encoding`` and ``backup_encoding`` methods have gone - replaced
3019
with the ``encode`` and ``decode`` methods.
3021
``fileerror`` and ``createempty`` options have become ``file_error`` and
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.
3028
Exceeding the maximum depth of recursion in string interpolation now
3029
raises an error ``InterpolationDepthError``.
3031
Specifying a value for interpolation which doesn't exist now raises an
3032
error ``MissingInterpolationOption`` (instead of merely being ignored).
3034
The ``writein`` method has been removed.
3036
The comments attribute is now a list (``inline_comments`` equates to the
3037
old comments attribute)
3042
``validate`` doesn't report *extra* values or sections.
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.
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).
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.
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 ?
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.
3066
Does it matter that we don't support the ':' divider, which is supported
3067
by ``ConfigParser`` ?
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.)
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
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.
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. : ::
3093
keyword = value1, 'value 2', "value 3"
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. : ::
3098
keyword = "single value",
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. : ::
3103
keyword = , # an empty list
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.
3116
Removed ``BOM_UTF8`` from ``__all__``.
3118
The ``BOM`` attribute has become a boolean. (Defaults to ``False``.) It is
3119
*only* ``True`` for the ``UTF16`` encoding.
3121
File like objects no longer need a ``seek`` attribute.
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
3128
Full unicode support added. New options/attributes ``encoding``,
3129
``default_encoding``.
3131
utf16 files decoded to unicode.
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.)
3137
File paths are *not* converted to absolute paths, relative paths will
3138
remain relative as the ``filename`` attribute.
3140
Fixed bug where ``final_comment`` wasn't returned if ``write`` is returning
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)
3150
Deprecated ``istrue``, replaced it with ``as_bool``.
3152
Added ``as_int`` and ``as_float``.
3154
utf8 and utf16 BOM handled in an endian agnostic way.
3159
Validation no longer done on the 'DEFAULT' section (only in the root
3160
level). This allows interpolation in configspecs.
3162
Change in validation syntax implemented in validate 0.2.1
3169
Added ``merge``, a recursive update.
3171
Added ``preserve_errors`` to ``validate`` and the ``flatten_errors``
3174
Thanks to Matthew Brett for suggestions and helping me iron out bugs.
3176
Fixed bug where a config file is *all* comment, the comment will now be
3177
``initial_comment`` rather than ``final_comment``.
3182
Fixed bug in ``create_empty``. Thanks to Paul Jimenez for the report.
3187
Fixed bug in ``Section.walk`` when transforming names as well as values.
3189
Added the ``istrue`` method. (Fetches the boolean equivalent of a string
3192
Fixed ``list_values=False`` - they are now only quoted/unquoted if they
3193
are multiline values.
3195
List values are written as ``item, item`` rather than ``item,item``.
3202
Fixed typo in ``write`` method. (Testing for the wrong value when resetting
3210
Fixed bug in ``setdefault`` - creating a new section *wouldn't* return
3211
a reference to the new section.
3216
Removed ``PositionError``.
3218
Allowed quotes around keys as documented.
3220
Fixed bug with commas in comments. (matched as a list value)
3227
Fixed bug in initialising ConfigObj from a ConfigObj.
3229
Changed the mailing list address.
3236
Fixed bug in ``Section.__delitem__`` oops.
3241
Interpolation is switched off before writing out files.
3243
Fixed bug in handling ``StringIO`` instances. (Thanks to report from
3244
"Gustavo Niemeyer" <gustavo@niemeyer.net>)
3246
Moved the doctests from the ``__init__`` method to a separate function.
3247
(For the sake of IDE calltips).
3254
String values unchanged by validation *aren't* reset. This preserves
3255
interpolation in string values.
3260
None from a default is turned to '' if stringify is off - because setting
3261
a value to None raises an error.
3270
Actually added the RepeatSectionError class ;-)
3275
If ``stringify`` is off - list values are preserved by the ``validate``
3283
Fixed ``simpleVal``.
3285
Added ``RepeatSectionError`` error if you have additional sections in a
3286
section with a ``__many__`` (repeated) section.
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
3294
Reshaped the ConfigObj._multiline method to better reflect its semantics
3296
Changed the "default_test" test in ConfigObj.validate to check the fix for
3297
the bug in validate.Validator.check
3304
Updated comments at top
3311
Implemented repeated sections.
3315
Added test for interpreter version: raises RuntimeError if earlier than
3323
Implemented default values in configspecs.
3327
Fixed naked except: clause in validate that was silencing the fact
3328
that Python2.2 does not have dict.pop
3335
Bug fix causing error if file didn't exist.
3342
Adjusted doctests for Python 2.2.3 compatibility
3349
Added the inline_comments attribute
3351
We now preserve and rewrite all comments in the config file
3353
configspec is now a section attribute
3355
The validate method changes values in place
3357
Added InterpolationError
3359
The errors now have line number, line, and message attributes. This
3360
simplifies error handling
3369
Fixed bug in Section.pop (now doesn't raise KeyError if a default value
3372
Replaced ``basestring`` with ``types.StringTypes``
3374
Removed the ``writein`` method
3383
Indentation in config file is not significant anymore, subsections are
3384
designated by repeating square brackets
3386
Adapted all tests and docs to the new format
3400
Reformatted final docstring in ReST format, indented it for easier folding
3402
Code tests converted to doctest format, and scattered them around
3403
in various docstrings
3405
Walk method rewritten using scalars and sections attributes
3412
Changed Validator and SimpleVal "test" methods to "check"
3419
Changed Section.sequence to Section.scalars and Section.sections
3421
Added Section.configspec
3423
Sections in the root section now have no extra indentation
3425
Comments now better supported in Section and preserved by ConfigObj
3427
Comments also written out
3429
Implemented initial_comment and final_comment
3431
A scalar value after a section will now raise an error
3436
Fixed a couple of bugs
3438
Can now pass a tuple instead of a list
3440
Simplified dict and walk methods
3442
Added __str__ to Section
3454
The stringify option implemented. On by default.
3459
Renamed private attributes with a single underscore prefix.
3461
Changes to interpolation - exceeding recursion depth, or specifying a
3462
missing value, now raise errors.
3464
Changes for Python 2.2 compatibility. (changed boolean tests - removed
3465
``is True`` and ``is False``)
3467
Added test for duplicate section and member (and fixed bug)
3481
Now properly handles values including comments and lists.
3483
Better error handling.
3485
String interpolation.
3487
Some options implemented.
3489
You can pass a Section a dictionary to initialise it.
3491
Setting a Section member to a dictionary will create a Section instance.
3498
Experimental reader.
3500
A reasonably elegant implementation - a basic reader in 160 lines of code.
3502
*A programming language is a medium of expression.* - Paul Graham
2459
"""*A programming language is a medium of expression.* - Paul Graham"""