blob: 2f3ca519f457a90cc8c2ad34eff010aa0f2c6627 [file] [log] [blame]
Guido van Rossum3d209861997-12-09 16:10:31 +00001"""Configuration file parser.
2
3A setup file consists of sections, lead by a "[section]" header,
4and followed by "name: value" entries, with continuations and such in
5the style of rfc822.
6
7The option values can contain format strings which refer to other
8values in the same section, or values in a special [DEFAULT] section.
9For example:
10
11 something: %(dir)s/whatever
12
13would resolve the "%(dir)s" to the value of dir. All reference
14expansions are done late, on demand.
15
16Intrinsic defaults can be specified by passing them into the
17ConfigParser constructor as a dictionary.
18
19class:
20
21ConfigParser -- responsible for for parsing a list of
22 configuration files, and managing the parsed database.
23
24 methods:
25
26 __init__(defaults=None) -- create the parser and specify a
27 dictionary of intrinsic defaults. The
28 keys must be strings, the values must
29 be appropriate for %()s string
30 interpolation. Note that `name' is
31 always an intrinsic default; it's value
32 is the section's name.
33
34 sections() -- return all the configuration section names, sans DEFAULT
35
36 options(section) -- return list of configuration options for the named
37 section
38
39 read(*filenames) -- read and parse the list of named configuration files
40
41 get(section, option, raw=0) -- return a string value for the named
42 option. All % interpolations are
43 expanded in the return values, based on
44 the defaults passed into the constructor
45 and the DEFAULT section.
46
47 getint(section, options) -- like get(), but convert value to an integer
48
49 getfloat(section, options) -- like get(), but convert value to a float
50
51 getboolean(section, options) -- like get(), but convert value to
52 a boolean (currently defined as 0
53 or 1, only)
54"""
55
56import sys
57import string
58import regex
59from types import ListType
60
61
62SECTHEAD_RE = "^\[\([-A-Za-z0-9]*\)\][" + string.whitespace + "]*$"
63secthead_cre = regex.compile(SECTHEAD_RE)
64OPTION_RE = "^\([-A-Za-z0-9.]+\)\(:\|[" + string.whitespace + "]*=\)\(.*\)$"
65option_cre = regex.compile(OPTION_RE)
66
67DEFAULTSECT = "DEFAULT"
68
69
70
71# exception classes
72class Error:
73 def __init__(self, msg=''):
74 self.__msg = msg
75 def __repr__(self):
76 return self.__msg
77
78class NoSectionError(Error):
79 def __init__(self, section):
80 Error.__init__(self, 'No section: %s' % section)
81 self.section = section
82
83class DuplicateSectionError(Error):
84 def __init__(self, section):
85 Error.__init__(self, "Section %s already exists" % section)
86 self.section = section
87
88class NoOptionError(Error):
89 def __init__(self, option, section):
90 Error.__init__(self, "No option `%s' in section: %s" %
91 (option, section))
92 self.option = option
93 self.section = section
94
95class InterpolationError(Error):
96 def __init__(self, reference, option, section):
97 Error.__init__(self,
98 "Bad value substitution: sect `%s', opt `%s', ref `%s'"
99 % (section, option, reference))
100 self.reference = reference
101 self.option = option
102 self.section = section
103
104
105
106class ConfigParser:
107 def __init__(self, defaults=None):
108 self.__sections = {}
109 if defaults is None:
110 self.__defaults = {}
111 else:
112 self.__defaults = defaults
113
114 def defaults(self):
115 return self.__defaults
116
117 def sections(self):
118 """Return a list of section names, excluding [DEFAULT]"""
119 # self.__sections will never have [DEFAULT] in it
120 return self.__sections.keys()
121
122 def add_section(self, section):
123 """Create a new section in the configuration.
124
125 Raise DuplicateSectionError if a section by the specified name
126 already exists.
127 """
128 if self.__sections.has_key(section):
129 raise DuplicateSectionError(section)
130 self.__sections[section] = {}
131
132 def has_section(self, section):
133 """Indicate whether the named section is present in the configuration.
134
135 The DEFAULT section is not acknowledged.
136 """
137 return self.__sections.has_key(section)
138
139 def options(self, section):
140 try:
141 opts = self.__sections[section].copy()
142 except KeyError:
143 raise NoSectionError(section)
144 opts.update(self.__defaults)
145 return opts.keys()
146
147 def read(self, filenames):
148 """Read and parse a list of filenames."""
149 if type(filenames) is type(''):
150 filenames = [filenames]
151 for file in filenames:
152 try:
153 fp = open(file, 'r')
154 self.__read(fp)
155 except IOError:
156 pass
157
158 def get(self, section, option, raw=0):
159 """Get an option value for a given section.
160
161 All % interpolations are expanded in the return values, based
162 on the defaults passed into the constructor.
163
164 The section DEFAULT is special.
165 """
166 try:
167 d = self.__sections[section].copy()
168 except KeyError:
169 if section == DEFAULTSECT:
170 d = {}
171 else:
172 raise NoSectionError(section)
173 d.update(self.__defaults)
174 option = string.lower(option)
175 try:
176 rawval = d[option]
177 except KeyError:
178 raise NoOptionError(option, section)
179 # do the string interpolation
180 if raw:
181 return rawval
182 try:
183 return rawval % d
184 except KeyError, key:
185 raise InterpolationError(key, option, section)
186
187 def __get(self, section, conv, option):
188 return conv(self.get(section, option))
189
190 def getint(self, section, option):
191 return self.__get(section, string.atoi, option)
192
193 def getfloat(self, section, option):
194 return self.__get(section, string.atof, option)
195
196 def getboolean(self, section, option):
197 v = self.get(section, option)
198 val = string.atoi(v)
199 if val not in (0, 1):
200 raise ValueError, 'Not a boolean: %s' % v
201 return val
202
203 def __read(self, fp):
204 """Parse a sectioned setup file.
205
206 The sections in setup file contains a title line at the top,
207 indicated by a name in square brackets (`[]'), plus key/value
208 options lines, indicated by `name: value' format lines.
209 Continuation are represented by an embedded newline then
210 leading whitespace. Blank lines, lines beginning with a '#',
211 and just about everything else is ignored.
212 """
213 cursect = None # None, or a dictionary
214 optname = None
215 lineno = 0
216 while 1:
217 line = fp.readline()
218 if not line:
219 break
220 lineno = lineno + 1
221 # comment or blank line?
222 if string.strip(line) == '' or line[0] in '#;':
223 continue
224 if string.lower(string.split(line)[0]) == 'rem' \
225 and line[0] == "r": # no leading whitespace
226 continue
227 # continuation line?
228 if line[0] in ' \t' and cursect <> None and optname:
229 value = string.strip(line)
230 if value:
231 cursect = cursect[optname] + '\n ' + value
232 # a section header?
233 elif secthead_cre.match(line) >= 0:
234 sectname = secthead_cre.group(1)
235 if self.__sections.has_key(sectname):
236 cursect = self.__sections[sectname]
237 elif sectname == DEFAULTSECT:
238 cursect = self.__defaults
239 else:
240 cursect = {'name': sectname}
241 self.__sections[sectname] = cursect
242 # So sections can't start with a continuation line.
243 optname = None
244 # an option line?
245 elif option_cre.match(line) >= 0:
246 optname, optval = option_cre.group(1, 3)
247 optname = string.lower(optname)
248 optval = string.strip(optval)
249 # allow empty values
250 if optval == '""':
251 optval = ''
252 cursect[optname] = optval
253 # an error
254 else:
255 print 'Error in %s at %d: %s', (fp.name, lineno, `line`)