254
270
nor a valid section marker line.
274
class ReloadError(IOError):
276
A 'reload' operation failed.
277
This exception is a subclass of ``IOError``.
280
IOError.__init__(self, 'reload failed, filename is not set.')
257
283
class DuplicateError(ConfigObjError):
259
285
The keyword or section specified already exists.
262
289
class ConfigspecError(ConfigObjError):
264
291
An error occured whilst parsing a configspec.
267
295
class InterpolationError(ConfigObjError):
268
296
"""Base class for the two interpolation errors."""
270
299
class InterpolationLoopError(InterpolationError):
271
300
"""Maximum interpolation depth exceeded in string interpolation."""
586
636
elif isinstance(value, (list, tuple)):
587
637
for entry in value:
588
638
if not isinstance(entry, StringTypes):
590
'Value is not a string "%s".' % entry)
639
raise TypeError('Value is not a string "%s".' % entry)
592
raise TypeError, 'Value is not a string "%s".' % value
641
raise TypeError('Value is not a string "%s".' % value)
593
642
dict.__setitem__(self, key, value)
595
645
def __delitem__(self, key):
596
646
"""Remove items from the sequence when deleting."""
597
647
dict. __delitem__(self, key)
664
723
self[key] = default
728
"""D.items() -> list of D's (key, value) pairs, as 2-tuples"""
669
729
return zip((self.scalars + self.sections), self.values())
733
"""D.keys() -> list of D's keys"""
673
734
return (self.scalars + self.sections)
675
737
def values(self):
738
"""D.values() -> list of D's values"""
677
739
return [self[key] for key in (self.scalars + self.sections)]
679
742
def iteritems(self):
743
"""D.iteritems() -> an iterator over the (key, value) items of D"""
681
744
return iter(self.items())
683
747
def iterkeys(self):
748
"""D.iterkeys() -> an iterator over the keys of D"""
685
749
return iter((self.scalars + self.sections))
687
751
__iter__ = iterkeys
689
754
def itervalues(self):
755
"""D.itervalues() -> an iterator over the values of D"""
691
756
return iter(self.values())
693
759
def __repr__(self):
760
"""x.__repr__() <==> repr(x)"""
694
761
return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(self[key])))
695
762
for key in (self.scalars + self.sections)])
697
764
__str__ = __repr__
765
__str__.__doc__ = "x.__str__() <==> str(x)"
699
768
# Extra methods - not in a normal dictionary
1022
1101
3.2000000000000002
1024
1103
return float(self[key])
1106
def restore_default(self, key):
1108
Restore (and return) default value for the specified key.
1110
This method will only work for a ConfigObj that was created
1111
with a configspec and has been validated.
1113
If there is no default value for this key, ``KeyError`` is raised.
1115
default = self.default_values[key]
1116
dict.__setitem__(self, key, default)
1117
if key not in self.defaults:
1118
self.defaults.append(key)
1122
def restore_defaults(self):
1124
Recursively restore default values to all members
1127
This method will only work for a ConfigObj that was created
1128
with a configspec and has been validated.
1130
It doesn't delete or modify entries without default values.
1132
for key in self.default_values:
1133
self.restore_default(key)
1135
for section in self.sections:
1136
self[section].restore_defaults()
1027
1139
class ConfigObj(Section):
1028
1140
"""An object to read, create, and write config files."""
1126
1238
'true': True, 'false': False,
1129
1242
def __init__(self, infile=None, options=None, **kwargs):
1131
Parse or create a config file object.
1244
Parse a config file or create a config file object.
1133
1246
``ConfigObj(infile=None, options=None, **kwargs)``
1248
# init the superclass
1249
Section.__init__(self, self, 0, self)
1135
1251
if infile is None:
1137
1253
if options is None:
1140
1256
options = dict(options)
1141
1258
# keyword arguments take precedence over an options dictionary
1142
1259
options.update(kwargs)
1143
# init the superclass
1144
Section.__init__(self, self, 0, self)
1146
1261
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
1262
# TODO: check the values too.
1263
for entry in options:
1264
if entry not in defaults:
1265
raise TypeError('Unrecognised option "%s".' % entry)
1152
1267
# Add any explicit options to the defaults
1153
1268
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
1269
self._initialise(defaults)
1270
configspec = defaults['configspec']
1271
self._original_configspec = configspec
1272
self._load(infile, configspec)
1275
def _load(self, infile, configspec):
1177
1276
if isinstance(infile, StringTypes):
1178
1277
self.filename = infile
1179
1278
if os.path.isfile(infile):
1180
infile = open(infile).read() or []
1279
h = open(infile, 'rb')
1280
infile = h.read() or []
1181
1282
elif self.file_error:
1182
1283
# raise an error if the file doesn't exist
1183
raise IOError, 'Config file not found: "%s".' % self.filename
1284
raise IOError('Config file not found: "%s".' % self.filename)
1185
1286
# file doesn't already exist
1186
1287
if self.create_empty:
1187
1288
# this is a good test that the filename specified
1188
# isn't impossible - like on a non existent device
1289
# isn't impossible - like on a non-existent device
1189
1290
h = open(infile, 'w')
1193
1295
elif isinstance(infile, (list, tuple)):
1194
1296
infile = list(infile)
1195
1298
elif isinstance(infile, dict):
1196
1299
# initialise self
1197
1300
# the Section class handles creating subsections
1198
1301
if isinstance(infile, ConfigObj):
1199
1302
# get a copy of our ConfigObj
1200
1303
infile = infile.dict()
1201
1305
for entry in infile:
1202
1306
self[entry] = infile[entry]
1203
1307
del self._errors
1204
if defaults['configspec'] is not None:
1205
self._handle_configspec(defaults['configspec'])
1309
if configspec is not None:
1310
self._handle_configspec(configspec)
1207
1312
self.configspec = None
1209
elif hasattr(infile, 'read'):
1315
elif getattr(infile, 'read', None) is not None:
1210
1316
# This supports file like objects
1211
1317
infile = infile.read() or []
1212
1318
# needs splitting into lines - but needs doing *after* decoding
1213
1319
# 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.')
1321
raise TypeError('infile must be a filename, file like object, or list of lines.')
1219
1324
# don't do it for the empty ConfigObj
1220
1325
infile = self._handle_bom(infile)
1253
1356
# delete private attributes
1254
1357
del self._errors
1256
if defaults['configspec'] is None:
1359
if configspec is None:
1257
1360
self.configspec = None
1259
self._handle_configspec(defaults['configspec'])
1362
self._handle_configspec(configspec)
1365
def _initialise(self, options=None):
1367
options = OPTION_DEFAULTS
1369
# initialise a few variables
1370
self.filename = None
1372
self.raise_errors = options['raise_errors']
1373
self.interpolation = options['interpolation']
1374
self.list_values = options['list_values']
1375
self.create_empty = options['create_empty']
1376
self.file_error = options['file_error']
1377
self.stringify = options['stringify']
1378
self.indent_type = options['indent_type']
1379
self.encoding = options['encoding']
1380
self.default_encoding = options['default_encoding']
1382
self.newlines = None
1383
self.write_empty_values = options['write_empty_values']
1384
self.unrepr = options['unrepr']
1386
self.initial_comment = []
1387
self.final_comment = []
1388
self.configspec = {}
1390
# Clear section attributes as well
1391
Section._initialise(self)
1261
1394
def __repr__(self):
1262
return 'ConfigObj({%s})' % ', '.join(
1263
[('%s: %s' % (repr(key), repr(self[key]))) for key in
1264
(self.scalars + self.sections)])
1395
return ('ConfigObj({%s})' %
1396
', '.join([('%s: %s' % (repr(key), repr(self[key])))
1397
for key in (self.scalars + self.sections)]))
1266
1400
def _handle_bom(self, infile):
1429
1569
reset_comment = False
1430
1570
comment_list.append(line)
1432
1573
if not done_start:
1433
1574
# preserve initial comment
1434
1575
self.initial_comment = comment_list
1435
1576
comment_list = []
1436
1577
done_start = True
1437
1579
reset_comment = True
1438
1580
# first we check if it's a section marker
1439
1581
mat = self._sectionmarker.match(line)
1440
1582
if mat is not None:
1441
1583
# is a section line
1442
(indent, sect_open, sect_name, sect_close, comment) = (
1584
(indent, sect_open, sect_name, sect_close, comment) = mat.groups()
1444
1585
if indent and (self.indent_type is None):
1445
1586
self.indent_type = indent
1446
1587
cur_depth = sect_open.count('[')
1447
1588
if cur_depth != sect_close.count(']'):
1449
"Cannot compute the section depth at line %s.",
1450
NestingError, infile, cur_index)
1589
self._handle_error("Cannot compute the section depth at line %s.",
1590
NestingError, infile, cur_index)
1453
1593
if cur_depth < this_section.depth:
1454
1594
# the new section is dropping back to a previous level
1456
parent = self._match_depth(
1596
parent = self._match_depth(this_section,
1459
1598
except SyntaxError:
1461
"Cannot compute nesting level at line %s.",
1462
NestingError, infile, cur_index)
1599
self._handle_error("Cannot compute nesting level at line %s.",
1600
NestingError, infile, cur_index)
1464
1602
elif cur_depth == this_section.depth:
1465
1603
# the new section is a sibling of the current section
1468
1606
# the new section is a child the current section
1469
1607
parent = this_section
1472
"Section too nested at line %s.",
1473
NestingError, infile, cur_index)
1609
self._handle_error("Section too nested at line %s.",
1610
NestingError, infile, cur_index)
1475
1612
sect_name = self._unquote(sect_name)
1476
1613
if parent.has_key(sect_name):
1478
'Duplicate section name at line %s.',
1479
DuplicateError, infile, cur_index)
1614
self._handle_error('Duplicate section name at line %s.',
1615
DuplicateError, infile, cur_index)
1481
1618
# create the new section
1482
1619
this_section = Section(
1653
1793
if self.stringify:
1654
1794
value = str(value)
1656
raise TypeError, 'Value "%s" is not a string.' % value
1660
wspace_plus = ' \r\t\n\v\t\'"'
1796
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))):
1801
no_lists_no_quotes = not self.list_values and '\n' not in value and '#' not in value
1802
need_triple = multiline and ((("'" in value) and ('"' in value)) or ('\n' in value ))
1803
hash_triple_quote = multiline and not need_triple and ("'" in value) and ('"' in value) and ('#' in value)
1804
check_for_single = (no_lists_no_quotes or not need_triple) and not hash_triple_quote
1806
if check_for_single:
1667
1807
if not self.list_values:
1668
1808
# we don't quote if ``list_values=False``
1670
1810
# for normal values either single or double quotes will do
1671
1811
elif '\n' in value:
1672
1812
# will only happen if multiline is off - e.g. '\n' in key
1673
raise ConfigObjError, ('Value "%s" cannot be safely quoted.' %
1813
raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
1675
1814
elif ((value[0] not in wspace_plus) and
1676
1815
(value[-1] not in wspace_plus) and
1677
1816
(',' not in value)):
1680
if ("'" in value) and ('"' in value):
1681
raise ConfigObjError, (
1682
'Value "%s" cannot be safely quoted.' % value)
1819
quot = self._get_single_quote(value)
1688
1821
# 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:
1822
quot = self._get_triple_quote(value)
1824
if quot == noquot and '#' in value and self.list_values:
1825
quot = self._get_single_quote(value)
1696
1827
return quot % value
1830
def _get_single_quote(self, value):
1831
if ("'" in value) and ('"' in value):
1832
raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
1840
def _get_triple_quote(self, value):
1841
if (value.find('"""') != -1) and (value.find("'''") != -1):
1842
raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
1843
if value.find('"""') == -1:
1698
1850
def _handle_value(self, value):
1768
1921
# we've got to the end of the config, oops...
1770
1923
mat = multi_line.match(line)
1771
1924
if mat is None:
1772
1925
# a badly formed line
1774
1927
(value, comment) = mat.groups()
1775
1928
return (newvalue + value, comment, cur_index)
1777
1931
def _handle_configspec(self, configspec):
1778
1932
"""Parse the configspec."""
1779
1933
# FIXME: Should we check that the configspec was created with the
1780
# correct settings ? (i.e. ``list_values=False``)
1934
# correct settings ? (i.e. ``list_values=False``)
1781
1935
if not isinstance(configspec, ConfigObj):
1783
configspec = ConfigObj(
1937
configspec = ConfigObj(configspec,
1788
1941
except ConfigObjError, e:
1789
1942
# FIXME: Should these errors have a reference
1790
# to the already parsed ConfigObj ?
1943
# to the already parsed ConfigObj ?
1791
1944
raise ConfigspecError('Parsing configspec failed: %s' % e)
1792
1945
except IOError, e:
1793
1946
raise IOError('Reading configspec failed: %s' % e)
1794
1948
self._set_configspec_value(configspec, self)
1796
1951
def _set_configspec_value(self, configspec, section):
1797
1952
"""Used to recursively set configspec values."""
1798
1953
if '__many__' in configspec.sections:
1799
1954
section.configspec['__many__'] = configspec['__many__']
1800
1955
if len(configspec.sections) > 1:
1801
1956
# FIXME: can we supply any useful information here ?
1802
raise RepeatSectionError
1803
if hasattr(configspec, 'initial_comment'):
1957
raise RepeatSectionError()
1959
if getattr(configspec, 'initial_comment', None) is not None:
1804
1960
section._configspec_initial_comment = configspec.initial_comment
1805
1961
section._configspec_final_comment = configspec.final_comment
1806
1962
section._configspec_encoding = configspec.encoding
1807
1963
section._configspec_BOM = configspec.BOM
1808
1964
section._configspec_newlines = configspec.newlines
1809
1965
section._configspec_indent_type = configspec.indent_type
1810
1967
for entry in configspec.scalars:
1811
1968
section._configspec_comments[entry] = configspec.comments[entry]
1812
section._configspec_inline_comments[entry] = (
1813
configspec.inline_comments[entry])
1969
section._configspec_inline_comments[entry] = configspec.inline_comments[entry]
1814
1970
section.configspec[entry] = configspec[entry]
1815
1971
section._order.append(entry)
1816
1973
for entry in configspec.sections:
1817
1974
if entry == '__many__':
1819
1977
section._cs_section_comments[entry] = configspec.comments[entry]
1820
section._cs_section_inline_comments[entry] = (
1821
configspec.inline_comments[entry])
1978
section._cs_section_inline_comments[entry] = configspec.inline_comments[entry]
1822
1979
if not section.has_key(entry):
1823
1980
section[entry] = {}
1824
1981
self._set_configspec_value(configspec[entry], section[entry])
1826
1984
def _handle_repeat(self, section, configspec):
1827
1985
"""Dynamically assign configspec for repeated section."""
1861
2022
val = self._decode_element(self._quote(this_entry))
1863
2024
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))
2025
return '%s%s%s%s%s' % (indent_string,
2026
self._decode_element(self._quote(entry, multiline=False)),
2027
self._a_to_u(' = '),
2029
self._decode_element(comment))
1871
2032
def _write_marker(self, indent_string, depth, entry, comment):
1872
2033
"""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))
2034
return '%s%s%s%s%s' % (indent_string,
2035
self._a_to_u('[' * depth),
2036
self._quote(self._decode_element(entry), multiline=False),
2037
self._a_to_u(']' * depth),
2038
self._decode_element(comment))
1880
2041
def _handle_comment(self, comment):
1881
2042
"""Deal with a comment."""
2028
2193
if section is None:
2029
2194
if self.configspec is None:
2030
raise ValueError, 'No configspec supplied.'
2195
raise ValueError('No configspec supplied.')
2031
2196
if preserve_errors:
2032
if VdtMissingValue is None:
2033
raise ImportError('Missing validate module.')
2197
# We do this once to remove a top level dependency on the validate module
2198
# Which makes importing configobj faster
2199
from validate import VdtMissingValue
2200
self._vdtMissingValue = VdtMissingValue
2036
2203
spec_section = section.configspec
2037
if copy and hasattr(section, '_configspec_initial_comment'):
2204
if copy and getattr(section, '_configspec_initial_comment', None) is not None:
2038
2205
section.initial_comment = section._configspec_initial_comment
2039
2206
section.final_comment = section._configspec_final_comment
2040
2207
section.encoding = section._configspec_encoding
2041
2208
section.BOM = section._configspec_BOM
2042
2209
section.newlines = section._configspec_newlines
2043
2210
section.indent_type = section._configspec_indent_type
2044
2212
if '__many__' in section.configspec:
2045
2213
many = spec_section['__many__']
2046
2214
# dynamically assign the configspecs
2130
2313
elif ret_false:
2319
"""Clear ConfigObj instance and restore to 'freshly created' state."""
2322
# FIXME: Should be done by '_initialise', but ConfigObj constructor (and reload)
2323
# requires an empty dictionary
2324
self.configspec = None
2325
# Just to be sure ;-)
2326
self._original_configspec = None
2331
Reload a ConfigObj from file.
2333
This method raises a ``ReloadError`` if the ConfigObj doesn't have
2334
a filename attribute pointing to a file.
2336
if not isinstance(self.filename, StringTypes):
2339
filename = self.filename
2340
current_options = {}
2341
for entry in OPTION_DEFAULTS:
2342
if entry == 'configspec':
2344
current_options[entry] = getattr(self, entry)
2346
configspec = self._original_configspec
2347
current_options['configspec'] = configspec
2350
self._initialise(current_options)
2351
self._load(filename, configspec)
2135
2355
class SimpleVal(object):