16
16
# http://lists.sourceforge.net/lists/listinfo/configobj-develop
17
17
# Comments, suggestions and bug reports welcome.
20
from __future__ import absolute_import
19
from __future__ import generators
22
INTP_VER = sys.version_info[:2]
24
raise RuntimeError("Python v.2.2 or later needed")
27
# Bzr modification: Disabled import of 'compiler' module
28
# bzr doesn't use the 'unrepr' feature of configobj, so importing compiler just
29
# wastes several milliseconds on every single bzr invocation.
30
# -- Andrew Bennetts, 2008-10-14
33
from types import StringTypes
34
from warnings import warn
39
36
from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE
40
37
except ImportError:
223
211
if not isinstance(imag, complex) or imag.real != 0.0:
224
212
raise UnknownType('Add')
227
215
def build_Getattr(self, o):
228
216
parent = self.build(o.expr)
229
217
return getattr(parent, o.attrname)
231
219
def build_UnarySub(self, o):
232
220
return -self.build_Const(o.getChildren()[0])
234
222
def build_UnaryAdd(self, o):
235
223
return self.build_Const(o.getChildren()[0])
244
return _builder.build(getObj(s))
228
return Builder().build(getObj(s))
230
def _splitlines(instring):
231
"""Split a string on lines, without losing line endings or truncating."""
248
234
class ConfigObjError(SyntaxError):
479
442
# Anything else: ignore completely, just return it unchanged
480
443
return None, match.group(), None
483
445
interpolation_engines = {
484
446
'configparser': ConfigParserInterpolation,
485
447
'template': TemplateInterpolation,
489
def __newobj__(cls, *args):
491
return cls.__new__(cls, *args)
493
450
class Section(dict):
495
452
A dictionary-like object that represents a section in a config file.
497
454
It does string interpolation if the 'interpolation' attribute
498
455
of the 'main' object is set to True.
500
457
Interpolation is tried first from this object, then from the 'DEFAULT'
501
458
section of this object, next from the parent and its 'DEFAULT' section,
502
459
and so on until the main object is reached.
504
461
A Section will behave like an ordered dictionary - following the
505
462
order of the ``scalars`` and ``sections`` attributes.
506
463
You can use this to change the order of members.
508
465
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)
521
468
def __init__(self, parent, depth, main, indict=None, name=None):
523
470
* parent is the section above
535
482
# level of nesting depth of this Section
536
483
self.depth = depth
484
# the sequence of scalar values in this Section
486
# the sequence of sections in this Section
537
488
# 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
490
# for comments :-)
553
491
self.comments = {}
554
492
self.inline_comments = {}
556
self.configspec = None
496
self._configspec_comments = {}
497
self._configspec_inline_comments = {}
498
self._cs_section_comments = {}
499
self._cs_section_inline_comments = {}
558
501
self.defaults = []
559
self.default_values = {}
503
# we do this explicitly so that __setitem__ is used properly
504
# (rather than just passing to ``dict.__init__``)
506
self[entry] = indict[entry]
562
508
def _interpolate(self, key, value):
581
527
# let the engine do the actual work
582
528
return engine.interpolate(key, value)
585
530
def __getitem__(self, key):
586
531
"""Fetch the item and do string interpolation."""
587
532
val = dict.__getitem__(self, key)
588
if self.main.interpolation and isinstance(val, basestring):
533
if self.main.interpolation and isinstance(val, StringTypes):
589
534
return self._interpolate(key, val)
593
537
def __setitem__(self, key, value, unrepr=False):
595
539
Correctly set a value.
597
541
Making dictionary values Section instances.
598
542
(We have to special case 'Section' instances - which are also dicts)
600
544
Keys must be strings.
601
545
Values need only be strings (or lists of strings) if
602
546
``main.stringify`` is set.
604
``unrepr`` must be set when setting a value to a dictionary, without
548
`unrepr`` must be set when setting a value to a dictionary, without
605
549
creating a new sub-section.
607
if not isinstance(key, basestring):
608
raise ValueError('The key "%s" is not a string.' % key)
551
if not isinstance(key, StringTypes):
552
raise ValueError, 'The key "%s" is not a string.' % key
610
553
# add the comment
611
if key not in self.comments:
554
if not self.comments.has_key(key):
612
555
self.comments[key] = []
613
556
self.inline_comments[key] = ''
614
557
# remove the entry from defaults
581
if not self.has_key(key):
639
582
self.scalars.append(key)
640
583
if not self.main.stringify:
641
if isinstance(value, basestring):
584
if isinstance(value, StringTypes):
643
586
elif isinstance(value, (list, tuple)):
644
587
for entry in value:
645
if not isinstance(entry, basestring):
646
raise TypeError('Value is not a string "%s".' % entry)
588
if not isinstance(entry, StringTypes):
590
'Value is not a string "%s".' % entry)
648
raise TypeError('Value is not a string "%s".' % value)
592
raise TypeError, 'Value is not a string "%s".' % value
649
593
dict.__setitem__(self, key, value)
652
595
def __delitem__(self, key):
653
596
"""Remove items from the sequence when deleting."""
654
597
dict. __delitem__(self, key)
690
627
del self.comments[key]
691
628
del self.inline_comments[key]
692
629
self.sections.remove(key)
693
if self.main.interpolation and isinstance(val, basestring):
630
if self.main.interpolation and isinstance(val, StringTypes):
694
631
return self._interpolate(key, val)
698
634
def popitem(self):
699
635
"""Pops the first (key,val)"""
700
636
sequence = (self.scalars + self.sections)
702
raise KeyError(": 'popitem(): dictionary is empty'")
638
raise KeyError, ": 'popitem(): dictionary is empty'"
703
639
key = sequence[0]
711
646
A version of clear that also affects scalars/sections
712
647
Also clears comments and configspec.
714
649
Leaves other attributes alone :
715
650
depth/main/parent are not affected
730
664
self[key] = default
735
"""D.items() -> list of D's (key, value) pairs, as 2-tuples"""
736
669
return zip((self.scalars + self.sections), self.values())
740
"""D.keys() -> list of D's keys"""
741
673
return (self.scalars + self.sections)
744
675
def values(self):
745
"""D.values() -> list of D's values"""
746
677
return [self[key] for key in (self.scalars + self.sections)]
749
679
def iteritems(self):
750
"""D.iteritems() -> an iterator over the (key, value) items of D"""
751
681
return iter(self.items())
754
683
def iterkeys(self):
755
"""D.iterkeys() -> an iterator over the keys of D"""
756
685
return iter((self.scalars + self.sections))
758
687
__iter__ = iterkeys
761
689
def itervalues(self):
762
"""D.itervalues() -> an iterator over the values of D"""
763
691
return iter(self.values())
766
693
def __repr__(self):
767
"""x.__repr__() <==> repr(x)"""
768
694
return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(self[key])))
769
695
for key in (self.scalars + self.sections)])
771
697
__str__ = __repr__
772
__str__.__doc__ = "x.__str__() <==> str(x)"
775
699
# Extra methods - not in a normal dictionary
779
703
Return a deepcopy of self as a dictionary.
781
705
All members that are ``Section`` instances are recursively turned to
782
706
ordinary dictionaries - by calling their ``dict`` method.
858
780
self.comments[newkey] = comm
859
781
self.inline_comments[newkey] = inline_comment
862
783
def walk(self, function, raise_errors=True,
863
784
call_on_sections=False, **keywargs):
865
786
Walk every member and call a function on the keyword and value.
867
788
Return a dictionary of the return values
869
790
If the function raises an exception, raise the errror
870
791
unless ``raise_errors=False``, in which case set the return value to
873
794
Any unrecognised keyword arguments you pass to walk, will be pased on
874
795
to the function you pass in.
876
797
Note: if ``call_on_sections`` is ``True`` then - on encountering a
877
798
subsection, *first* the function is called for the *whole* subsection,
878
799
and then recurses into it's members. This means your function must be
879
800
able to handle strings, dictionaries and lists. This allows you
880
801
to change the key of subsections as well as for ordinary members. The
881
802
return value when called on the whole subsection has to be discarded.
883
804
See the encode and decode methods for examples, including functions.
885
.. admonition:: caution
887
808
You can use ``walk`` to transform the names of members of a section
888
809
but you mustn't add or delete members.
890
811
>>> config = '''[XXXXsection]
891
812
... XXXXkey = XXXXvalue'''.splitlines()
892
813
>>> cfg = ConfigObj(config)
894
ConfigObj({'XXXXsection': {'XXXXkey': 'XXXXvalue'}})
815
{'XXXXsection': {'XXXXkey': 'XXXXvalue'}}
895
816
>>> def transform(section, key):
896
817
... val = section[key]
897
818
... newkey = key.replace('XXXX', 'CLIENT1')
867
def decode(self, encoding):
869
Decode all strings and values to unicode, using the specified encoding.
871
Works with subsections and list values.
873
Uses the ``walk`` method.
875
Testing ``encode`` and ``decode``.
877
>>> m.decode('ascii')
878
>>> def testuni(val):
879
... for entry in val:
880
... if not isinstance(entry, unicode):
881
... print >> sys.stderr, type(entry)
882
... raise AssertionError, 'decode failed.'
883
... if isinstance(val[entry], dict):
884
... testuni(val[entry])
885
... elif not isinstance(val[entry], unicode):
886
... raise AssertionError, 'decode failed.'
888
>>> m.encode('ascii')
892
warn('use of ``decode`` is deprecated.', DeprecationWarning)
893
def decode(section, key, encoding=encoding, warn=True):
896
if isinstance(val, (list, tuple)):
899
newval.append(entry.decode(encoding))
900
elif isinstance(val, dict):
903
newval = val.decode(encoding)
904
newkey = key.decode(encoding)
905
section.rename(key, newkey)
906
section[newkey] = newval
907
# using ``call_on_sections`` allows us to modify section names
908
self.walk(decode, call_on_sections=True)
910
def encode(self, encoding):
912
Encode all strings and values from unicode,
913
using the specified encoding.
915
Works with subsections and list values.
916
Uses the ``walk`` method.
918
warn('use of ``encode`` is deprecated.', DeprecationWarning)
919
def encode(section, key, encoding=encoding):
922
if isinstance(val, (list, tuple)):
925
newval.append(entry.encode(encoding))
926
elif isinstance(val, dict):
929
newval = val.encode(encoding)
930
newkey = key.encode(encoding)
931
section.rename(key, newkey)
932
section[newkey] = newval
933
self.walk(encode, call_on_sections=True)
935
def istrue(self, key):
936
"""A deprecated version of ``as_bool``."""
937
warn('use of ``istrue`` is deprecated. Use ``as_bool`` method '
938
'instead.', DeprecationWarning)
939
return self.as_bool(key)
947
941
def as_bool(self, key):
949
943
Accepts a key as input. The corresponding value must be a string or
950
944
the objects (``True`` or 1) or (``False`` or 0). We allow 0 and 1 to
951
945
retain compatibility with Python 2.2.
953
If the string is one of ``True``, ``On``, ``Yes``, or ``1`` it returns
947
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
950
If the string is one of ``False``, ``Off``, ``No``, or ``0`` it returns
959
953
``as_bool`` is not case sensitive.
961
955
Any other input will raise a ``ValueError``.
963
957
>>> a = ConfigObj()
964
958
>>> a['a'] = 'fish'
965
959
>>> a.as_bool('a')
982
if not isinstance(val, basestring):
983
# TODO: Why do we raise a KeyError here?
976
if not isinstance(val, StringTypes):
986
979
return self.main._bools[val.lower()]
988
981
raise ValueError('Value "%s" is neither True nor False' % val)
991
983
def as_int(self, key):
993
985
A convenience method which coerces the specified value to an integer.
995
987
If the value is an invalid literal for ``int``, a ``ValueError`` will
998
990
>>> a = ConfigObj()
999
991
>>> a['a'] = 'fish'
1000
992
>>> a.as_int('a')
1001
993
Traceback (most recent call last):
1002
ValueError: invalid literal for int() with base 10: 'fish'
994
ValueError: invalid literal for int(): fish
1003
995
>>> a['b'] = '1'
1004
996
>>> a.as_int('b')
1006
998
>>> a['b'] = '3.2'
1007
999
>>> a.as_int('b')
1008
1000
Traceback (most recent call last):
1009
ValueError: invalid literal for int() with base 10: '3.2'
1001
ValueError: invalid literal for int(): 3.2
1011
1003
return int(self[key])
1014
1005
def as_float(self, key):
1016
1007
A convenience method which coerces the specified value to a float.
1018
1009
If the value is an invalid literal for ``float``, a ``ValueError`` will
1021
1012
>>> a = ConfigObj()
1022
1013
>>> a['a'] = 'fish'
1023
1014
>>> a.as_float('a')
1031
1022
3.2000000000000002
1033
1024
return float(self[key])
1036
def as_list(self, key):
1038
A convenience method which fetches the specified value, guaranteeing
1053
if isinstance(result, (tuple, list)):
1058
def restore_default(self, key):
1060
Restore (and return) default value for the specified key.
1062
This method will only work for a ConfigObj that was created
1063
with a configspec and has been validated.
1065
If there is no default value for this key, ``KeyError`` is raised.
1067
default = self.default_values[key]
1068
dict.__setitem__(self, key, default)
1069
if key not in self.defaults:
1070
self.defaults.append(key)
1074
def restore_defaults(self):
1076
Recursively restore default values to all members
1079
This method will only work for a ConfigObj that was created
1080
with a configspec and has been validated.
1082
It doesn't delete or modify entries without default values.
1084
for key in self.default_values:
1085
self.restore_default(key)
1087
for section in self.sections:
1088
self[section].restore_defaults()
1091
1027
class ConfigObj(Section):
1092
1028
"""An object to read, create, and write config files."""
1190
1126
'true': True, 'false': False,
1194
def __init__(self, infile=None, options=None, _inspec=False, **kwargs):
1129
def __init__(self, infile=None, options=None, **kwargs):
1196
Parse a config file or create a config file object.
1131
Parse or create a config file object.
1198
1133
``ConfigObj(infile=None, options=None, **kwargs)``
1200
self._inspec = _inspec
1140
options = dict(options)
1141
# keyword arguments take precedence over an options dictionary
1142
options.update(kwargs)
1201
1143
# init the superclass
1202
1144
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
1146
defaults = OPTION_DEFAULTS.copy()
1147
for entry in options.keys():
1148
if entry not in defaults.keys():
1149
raise TypeError, 'Unrecognised option "%s".' % entry
1213
1150
# TODO: check the values too.
1214
for entry in options:
1215
if entry not in defaults:
1216
raise TypeError('Unrecognised option "%s".' % entry)
1218
1152
# Add any explicit options to the defaults
1219
1153
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):
1155
# initialise a few variables
1156
self.filename = None
1158
self.raise_errors = defaults['raise_errors']
1159
self.interpolation = defaults['interpolation']
1160
self.list_values = defaults['list_values']
1161
self.create_empty = defaults['create_empty']
1162
self.file_error = defaults['file_error']
1163
self.stringify = defaults['stringify']
1164
self.indent_type = defaults['indent_type']
1165
self.encoding = defaults['encoding']
1166
self.default_encoding = defaults['default_encoding']
1168
self.newlines = None
1169
self.write_empty_values = defaults['write_empty_values']
1170
self.unrepr = defaults['unrepr']
1172
self.initial_comment = []
1173
self.final_comment = []
1175
self._terminated = False
1177
if isinstance(infile, StringTypes):
1228
1178
self.filename = infile
1229
1179
if os.path.isfile(infile):
1230
h = open(infile, 'rb')
1231
infile = h.read() or []
1180
infile = open(infile).read() or []
1233
1181
elif self.file_error:
1234
1182
# raise an error if the file doesn't exist
1235
raise IOError('Config file not found: "%s".' % self.filename)
1183
raise IOError, 'Config file not found: "%s".' % self.filename
1237
1185
# file doesn't already exist
1238
1186
if self.create_empty:
1239
1187
# this is a good test that the filename specified
1240
# isn't impossible - like on a non-existent device
1188
# isn't impossible - like on a non existent device
1241
1189
h = open(infile, 'w')
1246
1193
elif isinstance(infile, (list, tuple)):
1247
1194
infile = list(infile)
1249
1195
elif isinstance(infile, dict):
1250
1196
# initialise self
1251
1197
# the Section class handles creating subsections
1252
1198
if isinstance(infile, ConfigObj):
1253
1199
# get a copy of our ConfigObj
1254
1200
infile = infile.dict()
1256
1201
for entry in infile:
1257
1202
self[entry] = infile[entry]
1258
1203
del self._errors
1260
if configspec is not None:
1261
self._handle_configspec(configspec)
1204
if defaults['configspec'] is not None:
1205
self._handle_configspec(defaults['configspec'])
1263
1207
self.configspec = None
1266
elif getattr(infile, 'read', MISSING) is not MISSING:
1209
elif hasattr(infile, 'read'):
1267
1210
# This supports file like objects
1268
1211
infile = infile.read() or []
1269
1212
# needs splitting into lines - but needs doing *after* decoding
1270
1213
# in case it's not an 8 bit encoding
1272
raise TypeError('infile must be a filename, file like object, or list of lines.')
1215
raise TypeError, ('infile must be a filename,'
1216
' file like object, or list of lines.')
1275
1219
# don't do it for the empty ConfigObj
1276
1220
infile = self._handle_bom(infile)
1307
1253
# delete private attributes
1308
1254
del self._errors
1310
if configspec is None:
1256
if defaults['configspec'] is None:
1311
1257
self.configspec = None
1313
self._handle_configspec(configspec)
1316
def _initialise(self, options=None):
1318
options = OPTION_DEFAULTS
1320
# initialise a few variables
1321
self.filename = None
1323
self.raise_errors = options['raise_errors']
1324
self.interpolation = options['interpolation']
1325
self.list_values = options['list_values']
1326
self.create_empty = options['create_empty']
1327
self.file_error = options['file_error']
1328
self.stringify = options['stringify']
1329
self.indent_type = options['indent_type']
1330
self.encoding = options['encoding']
1331
self.default_encoding = options['default_encoding']
1333
self.newlines = None
1334
self.write_empty_values = options['write_empty_values']
1335
self.unrepr = options['unrepr']
1337
self.initial_comment = []
1338
self.final_comment = []
1339
self.configspec = None
1342
self.list_values = False
1344
# Clear section attributes as well
1345
Section._initialise(self)
1259
self._handle_configspec(defaults['configspec'])
1348
1261
def __repr__(self):
1349
return ('ConfigObj({%s})' %
1350
', '.join([('%s: %s' % (repr(key), repr(self[key])))
1351
for key in (self.scalars + self.sections)]))
1262
return 'ConfigObj({%s})' % ', '.join(
1263
[('%s: %s' % (repr(key), repr(self[key]))) for key in
1264
(self.scalars + self.sections)])
1354
1266
def _handle_bom(self, infile):
1356
1268
Handle any BOM, and decode if necessary.
1358
1270
If an encoding is specified, that *must* be used - but the BOM should
1359
1271
still be removed (and the BOM attribute set).
1361
1273
(If the encoding is wrongly specified, then a BOM for an alternative
1362
1274
encoding won't be discovered or removed.)
1364
1276
If an encoding is not specified, UTF8 or UTF16 BOM will be detected and
1365
1277
removed. The BOM attribute will be set. UTF16 will be decoded to
1368
1280
NOTE: This method must not be called with an empty ``infile``.
1370
1282
Specifying the *wrong* encoding is likely to cause a
1371
1283
``UnicodeDecodeError``.
1373
1285
``infile`` must always be returned as a list of lines, but may be
1374
1286
passed in as a single string.
1523
1429
reset_comment = False
1524
1430
comment_list.append(line)
1527
1432
if not done_start:
1528
1433
# preserve initial comment
1529
1434
self.initial_comment = comment_list
1530
1435
comment_list = []
1531
1436
done_start = True
1533
1437
reset_comment = True
1534
1438
# first we check if it's a section marker
1535
1439
mat = self._sectionmarker.match(line)
1536
1440
if mat is not None:
1537
1441
# is a section line
1538
(indent, sect_open, sect_name, sect_close, comment) = mat.groups()
1442
(indent, sect_open, sect_name, sect_close, comment) = (
1539
1444
if indent and (self.indent_type is None):
1540
1445
self.indent_type = indent
1541
1446
cur_depth = sect_open.count('[')
1542
1447
if cur_depth != sect_close.count(']'):
1543
self._handle_error("Cannot compute the section depth at line %s.",
1544
NestingError, infile, cur_index)
1449
"Cannot compute the section depth at line %s.",
1450
NestingError, infile, cur_index)
1547
1453
if cur_depth < this_section.depth:
1548
1454
# the new section is dropping back to a previous level
1550
parent = self._match_depth(this_section,
1456
parent = self._match_depth(
1552
1459
except SyntaxError:
1553
self._handle_error("Cannot compute nesting level at line %s.",
1554
NestingError, infile, cur_index)
1461
"Cannot compute nesting level at line %s.",
1462
NestingError, infile, cur_index)
1556
1464
elif cur_depth == this_section.depth:
1557
1465
# the new section is a sibling of the current section
1560
1468
# the new section is a child the current section
1561
1469
parent = this_section
1563
self._handle_error("Section too nested at line %s.",
1564
NestingError, infile, cur_index)
1472
"Section too nested at line %s.",
1473
NestingError, infile, cur_index)
1566
1475
sect_name = self._unquote(sect_name)
1567
if sect_name in parent:
1568
self._handle_error('Duplicate section name at line %s.',
1569
DuplicateError, infile, cur_index)
1476
if parent.has_key(sect_name):
1478
'Duplicate section name at line %s.',
1479
DuplicateError, infile, cur_index)
1572
1481
# create the new section
1573
1482
this_section = Section(
1666
1577
self.final_comment = comment_list
1667
1578
self.list_values = temp_list_values
1670
1580
def _match_depth(self, sect, depth):
1672
1582
Given a section and a depth level, walk back through the sections
1673
1583
parents to see if the depth level matches a previous section.
1675
1585
Return a reference to the right section,
1676
1586
or raise a SyntaxError.
1678
1588
while depth < sect.depth:
1679
1589
if sect is sect.parent:
1680
1590
# we've reached the top level already
1682
1592
sect = sect.parent
1683
1593
if sect.depth == depth:
1685
1595
# shouldn't get here
1689
1598
def _handle_error(self, text, ErrorClass, infile, cur_index):
1691
1600
Handle an error according to the error settings.
1693
1602
Either raise the error or store it.
1694
1603
The error will have occured at ``cur_index``
1704
1613
# reraise when parsing has finished
1705
1614
self._errors.append(error)
1708
1616
def _unquote(self, value):
1709
1617
"""Return an unquoted version of a value"""
1710
1618
if (value[0] == value[-1]) and (value[0] in ('"', "'")):
1711
1619
value = value[1:-1]
1715
1622
def _quote(self, value, multiline=True):
1717
1624
Return a safely quoted version of a value.
1719
1626
Raise a ConfigObjError if the value cannot be safely quoted.
1720
1627
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.
1630
Don't quote values that don't need it.
1631
Recursively quote members of a list and return a comma joined list.
1632
Multiline is ``False`` for lists.
1633
Obey list syntax for empty and single member lists.
1728
1635
If ``list_values=False`` then the value is only quoted if it contains
1729
a ``\\n`` (is multiline) or '#'.
1636
a ``\n`` (is multiline).
1731
1638
If ``write_empty_values`` is set, and the value is an empty string, it
1732
1639
won't be quoted.
1743
1649
return self._quote(value[0], multiline=False) + ','
1744
1650
return ', '.join([self._quote(val, multiline=False)
1745
1651
for val in value])
1746
if not isinstance(value, basestring):
1652
if not isinstance(value, StringTypes):
1747
1653
if self.stringify:
1748
1654
value = str(value)
1750
raise TypeError('Value "%s" is not a string.' % value)
1656
raise TypeError, 'Value "%s" is not a string.' % value
1660
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:
1665
if (not self.list_values and '\n' not in value) or not (multiline and
1666
((("'" in value) and ('"' in value)) or ('\n' in value))):
1761
1667
if not self.list_values:
1762
1668
# we don't quote if ``list_values=False``
1764
1670
# for normal values either single or double quotes will do
1765
1671
elif '\n' in value:
1766
1672
# will only happen if multiline is off - e.g. '\n' in key
1767
raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
1673
raise ConfigObjError, ('Value "%s" cannot be safely quoted.' %
1768
1675
elif ((value[0] not in wspace_plus) and
1769
1676
(value[-1] not in wspace_plus) and
1770
1677
(',' not in value)):
1773
quot = self._get_single_quote(value)
1680
if ("'" in value) and ('"' in value):
1681
raise ConfigObjError, (
1682
'Value "%s" cannot be safely quoted.' % value)
1775
1688
# 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)
1689
if (value.find('"""') != -1) and (value.find("'''") != -1):
1690
raise ConfigObjError, (
1691
'Value "%s" cannot be safely quoted.' % value)
1692
if value.find('"""') == -1:
1781
1696
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
1698
def _handle_value(self, value):
1808
1700
Given a value string, unquote, remove comment,
1809
1701
handle lists. (including empty and single member lists)
1812
# Parsing a configspec so don't handle comments
1814
1703
# do we look for lists in values ?
1815
1704
if not self.list_values:
1816
1705
mat = self._nolistvalue.match(value)
1817
1706
if mat is None:
1819
1708
# NOTE: we don't unquote here
1820
1709
return mat.groups()
1880
1768
# we've got to the end of the config, oops...
1882
1770
mat = multi_line.match(line)
1883
1771
if mat is None:
1884
1772
# a badly formed line
1886
1774
(value, comment) = mat.groups()
1887
1775
return (newvalue + value, comment, cur_index)
1890
1777
def _handle_configspec(self, configspec):
1891
1778
"""Parse the configspec."""
1892
# FIXME: Should we check that the configspec was created with the
1893
# correct settings ? (i.e. ``list_values=False``)
1779
# FIXME: Should we check that the configspec was created with the
1780
# correct settings ? (i.e. ``list_values=False``)
1894
1781
if not isinstance(configspec, ConfigObj):
1896
configspec = ConfigObj(configspec,
1783
configspec = ConfigObj(
1900
1788
except ConfigObjError, e:
1901
1789
# FIXME: Should these errors have a reference
1902
# to the already parsed ConfigObj ?
1790
# to the already parsed ConfigObj ?
1903
1791
raise ConfigspecError('Parsing configspec failed: %s' % e)
1904
1792
except IOError, e:
1905
1793
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
1794
self._set_configspec_value(configspec, self)
1796
def _set_configspec_value(self, configspec, section):
1797
"""Used to recursively set configspec values."""
1798
if '__many__' in configspec.sections:
1799
section.configspec['__many__'] = configspec['__many__']
1800
if len(configspec.sections) > 1:
1801
# FIXME: can we supply any useful information here ?
1802
raise RepeatSectionError
1803
if hasattr(configspec, 'initial_comment'):
1804
section._configspec_initial_comment = configspec.initial_comment
1805
section._configspec_final_comment = configspec.final_comment
1806
section._configspec_encoding = configspec.encoding
1807
section._configspec_BOM = configspec.BOM
1808
section._configspec_newlines = configspec.newlines
1809
section._configspec_indent_type = configspec.indent_type
1810
for entry in configspec.scalars:
1811
section._configspec_comments[entry] = configspec.comments[entry]
1812
section._configspec_inline_comments[entry] = (
1813
configspec.inline_comments[entry])
1814
section.configspec[entry] = configspec[entry]
1815
section._order.append(entry)
1923
1816
for entry in configspec.sections:
1924
1817
if entry == '__many__':
1926
if entry not in section:
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]
1819
section._cs_section_comments[entry] = configspec.comments[entry]
1820
section._cs_section_inline_comments[entry] = (
1821
configspec.inline_comments[entry])
1822
if not section.has_key(entry):
1824
self._set_configspec_value(configspec[entry], section[entry])
1826
def _handle_repeat(self, section, configspec):
1827
"""Dynamically assign configspec for repeated section."""
1829
section_keys = configspec.sections
1830
scalar_keys = configspec.scalars
1831
except AttributeError:
1832
section_keys = [entry for entry in configspec
1833
if isinstance(configspec[entry], dict)]
1834
scalar_keys = [entry for entry in configspec
1835
if not isinstance(configspec[entry], dict)]
1836
if '__many__' in section_keys and len(section_keys) > 1:
1837
# FIXME: can we supply any useful information here ?
1838
raise RepeatSectionError
1841
for entry in scalar_keys:
1842
val = configspec[entry]
1843
scalars[entry] = val
1844
for entry in section_keys:
1845
val = configspec[entry]
1846
if entry == '__many__':
1847
scalars[entry] = val
1849
sections[entry] = val
1851
section.configspec = scalars
1852
for entry in sections:
1853
if not section.has_key(entry):
1855
self._handle_repeat(section[entry], sections[entry])
1938
1857
def _write_line(self, indent_string, entry, this_entry, comment):
1939
1858
"""Write an individual line, for the write method"""
1942
1861
val = self._decode_element(self._quote(this_entry))
1944
1863
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))
1864
return '%s%s%s%s%s' % (
1866
self._decode_element(self._quote(entry, multiline=False)),
1867
self._a_to_u(' = '),
1869
self._decode_element(comment))
1952
1871
def _write_marker(self, indent_string, depth, entry, comment):
1953
1872
"""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))
1873
return '%s%s%s%s%s' % (
1875
self._a_to_u('[' * depth),
1876
self._quote(self._decode_element(entry), multiline=False),
1877
self._a_to_u(']' * depth),
1878
self._decode_element(comment))
1961
1880
def _handle_comment(self, comment):
1962
1881
"""Deal with a comment."""
2073
1989
h.write(output)
2077
1992
def validate(self, validator, preserve_errors=False, copy=False,
2080
1995
Test the ConfigObj against a configspec.
2082
1997
It uses the ``validator`` object from *validate.py*.
2084
1999
To run ``validate`` on the current ConfigObj, call: ::
2086
2001
test = config.validate(validator)
2088
2003
(Normally having previously passed in the configspec when the ConfigObj
2089
2004
was created - you can dynamically assign a dictionary of checks to the
2090
2005
``configspec`` attribute of a section though).
2092
2007
It returns ``True`` if everything passes, or a dictionary of
2093
2008
pass/fails (True/False). If every member of a subsection passes, it
2094
2009
will just have the value ``True``. (It also returns ``False`` if all
2097
2012
In addition, it converts the values from strings to their native
2098
2013
types if their checks pass (and ``stringify`` is set).
2100
2015
If ``preserve_errors`` is ``True`` (``False`` is default) then instead
2101
2016
of a marking a fail with a ``False``, it will preserve the actual
2102
2017
exception object. This can contain info about the reason for failure.
2103
For example the ``VdtValueTooSmallError`` indicates that the value
2018
For example the ``VdtValueTooSmallError`` indeicates that the value
2104
2019
supplied was too small. If a value (or section) is missing it will
2105
2020
still be marked as ``False``.
2107
2022
You must have the validate module to use ``preserve_errors=True``.
2109
2024
You can then use the ``flatten_errors`` function to turn your nested
2110
2025
results dictionary into a flattened list of failures - useful for
2111
2026
displaying meaningful error messages.
2113
2028
if section is None:
2114
2029
if self.configspec is None:
2115
raise ValueError('No configspec supplied.')
2030
raise ValueError, 'No configspec supplied.'
2116
2031
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
2032
if VdtMissingValue is None:
2033
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):
2036
spec_section = section.configspec
2037
if copy and hasattr(section, '_configspec_initial_comment'):
2038
section.initial_comment = section._configspec_initial_comment
2039
section.final_comment = section._configspec_final_comment
2040
section.encoding = section._configspec_encoding
2041
section.BOM = section._configspec_BOM
2042
section.newlines = section._configspec_newlines
2043
section.indent_type = section._configspec_indent_type
2044
if '__many__' in section.configspec:
2045
many = spec_section['__many__']
2046
# dynamically assign the configspecs
2047
# for the sections below
2048
for entry in section.sections:
2049
self._handle_repeat(section[entry], many)
2054
order = [k for k in section._order if k in spec_section]
2055
order += [k for k in spec_section if k not in order]
2057
if entry == '__many__':
2059
if (not entry in section.scalars) or (entry in section.defaults):
2061
# or entries from defaults
2064
if copy and not entry in section.scalars:
2066
section.comments[entry] = (
2067
section._configspec_comments.get(entry, []))
2068
section.inline_comments[entry] = (
2069
section._configspec_inline_comments.get(entry, ''))
2073
val = section[entry]
2138
check = validator.check(spec,
2075
check = validator.check(spec_section[entry],
2140
2077
missing=missing
2142
2079
except validator.baseErrorClass, e:
2143
if not preserve_errors or isinstance(e, self._vdtMissingValue):
2080
if not preserve_errors or isinstance(e, VdtMissingValue):
2144
2081
out[entry] = False
2146
2083
# preserve the error
2181
2103
section[entry] = check
2182
2104
if not copy and missing and entry not in section.defaults:
2183
2105
section.defaults.append(entry)
2184
return ret_true, ret_false
2191
unvalidated = [k for k in section.scalars if k not in configspec]
2192
incorrect_sections = [k for k in configspec.sections if k in section.scalars]
2193
incorrect_scalars = [k for k in configspec.scalars if k in section.sections]
2195
for entry in configspec.scalars:
2196
if entry in ('__many__', '___many___'):
2200
if (not entry in section.scalars) or (entry in section.defaults):
2202
# or entries from defaults
2205
if copy and not entry in section.scalars:
2207
section.comments[entry] = (
2208
configspec.comments.get(entry, []))
2209
section.inline_comments[entry] = (
2210
configspec.inline_comments.get(entry, ''))
2214
val = section[entry]
2216
ret_true, ret_false = validate_entry(entry, configspec[entry], val,
2217
missing, ret_true, ret_false)
2220
if '__many__' in configspec.scalars:
2221
many = configspec['__many__']
2222
elif '___many___' in configspec.scalars:
2223
many = configspec['___many___']
2225
if many is not None:
2226
for entry in unvalidated:
2227
val = section[entry]
2228
ret_true, ret_false = validate_entry(entry, many, val, False,
2229
ret_true, ret_false)
2231
for entry in incorrect_scalars:
2233
if not preserve_errors:
2237
msg = 'Value %r was provided as a section' % entry
2238
out[entry] = validator.baseErrorClass(msg)
2239
for entry in incorrect_sections:
2241
if not preserve_errors:
2245
msg = 'Section %r was provided as a single value' % entry
2246
out[entry] = validator.baseErrorClass(msg)
2248
2107
# Missing sections will have been created as empty ones when the
2249
2108
# configspec was read.
2250
2109
for entry in section.sections:
2251
2110
# FIXME: this means DEFAULT is not copied in copy mode
2252
2111
if section is self and entry == 'DEFAULT':
2254
if section[entry].configspec is None:
2257
section.comments[entry] = configspec.comments.get(entry, [])
2258
section.inline_comments[entry] = configspec.inline_comments.get(entry, '')
2259
check = self.validate(validator, preserve_errors=preserve_errors, copy=copy, section=section[entry])
2114
section.comments[entry] = section._cs_section_comments[entry]
2115
section.inline_comments[entry] = (
2116
section._cs_section_inline_comments[entry])
2117
check = self.validate(validator, preserve_errors=preserve_errors,
2118
copy=copy, section=section[entry])
2260
2119
out[entry] = check
2261
2120
if check == False:
2262
2121
ret_true = False
2271
2130
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
2135
class SimpleVal(object):
2315
2137
A simple validator.
2316
2138
Can be used to check that all members expected are present.
2318
2140
To use it, provide a configspec with all your members in (the value given
2319
2141
will be ignored). Pass an instance of ``SimpleVal`` to the ``validate``
2320
2142
method of your ``ConfigObj``. ``validate`` will return ``True`` if all
2321
2143
members are present, or a dictionary with True/False meaning
2322
2144
present/missing. (Whole missing sections will be replaced with ``False``)
2325
2147
def __init__(self):
2326
2148
self.baseErrorClass = ConfigObjError
2328
2150
def check(self, check, member, missing=False):
2329
2151
"""A dummy check method, always returns the value unchanged."""
2331
raise self.baseErrorClass()
2153
raise self.baseErrorClass
2335
2156
# Check / processing functions for options
2336
2157
def flatten_errors(cfg, res, levels=None, results=None):
2338
2159
An example function that will turn a nested dictionary of results
2339
2160
(as returned by ``ConfigObj.validate``) into a flat list.
2341
2162
``cfg`` is the ConfigObj instance being checked, ``res`` is the results
2342
2163
dictionary returned by ``validate``.
2344
2165
(This is a recursive function, so you shouldn't use the ``levels`` or
2345
``results`` arguments - they are used by the function.)
2166
``results`` arguments - they are used by the function.
2347
2168
Returns a list of keys that failed. Each member of the list is a tuple :
2351
2171
([list of sections...], key, result)
2353
2173
If ``validate`` was called with ``preserve_errors=False`` (the default)
2354
2174
then ``result`` will always be ``False``.
2356
2176
*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``.
2179
If the section was missing then key will be ``None``.
2362
2181
If the value (or section) was missing then ``result`` will be ``False``.
2364
2183
If ``validate`` was called with ``preserve_errors=True`` and a value
2365
2184
was present, but failed the check, then ``result`` will be the exception
2366
2185
object returned. You can use this as a string that describes the failure.
2368
2187
For example *The value "3" is of the wrong type*.
2370
2189
>>> import validate
2371
2190
>>> vtor = validate.Validator()
2372
2191
>>> my_ini = '''