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