Statistics
| Revision:

root / tags / v1_0_2_Build_904 / extensions / extScripting / scripts / jython / Lib / ConfigParser.py @ 10724

History | View | Annotate | Download (16.8 KB)

1 5782 jmvivo
"""Configuration file parser.
2

3
A setup file consists of sections, lead by a "[section]" header,
4
and followed by "name: value" entries, with continuations and such in
5
the style of RFC 822.
6

7
The option values can contain format strings which refer to other values in
8
the same section, or values in a special [DEFAULT] section.
9

10
For example:
11

12
    something: %(dir)s/whatever
13

14
would resolve the "%(dir)s" to the value of dir.  All reference
15
expansions are done late, on demand.
16

17
Intrinsic defaults can be specified by passing them into the
18
ConfigParser constructor as a dictionary.
19

20
class:
21

22
ConfigParser -- responsible for for parsing a list of
23
                configuration files, and managing the parsed database.
24

25
    methods:
26

27
    __init__(defaults=None)
28
        create the parser and specify a dictionary of intrinsic defaults.  The
29
        keys must be strings, the values must be appropriate for %()s string
30
        interpolation.  Note that `__name__' is always an intrinsic default;
31
        it's value is the section's name.
32

33
    sections()
34
        return all the configuration section names, sans DEFAULT
35

36
    has_section(section)
37
        return whether the given section exists
38

39
    has_option(section, option)
40
        return whether the given option exists in the given section
41

42
    options(section)
43
        return list of configuration options for the named section
44

45
    has_option(section, option)
46
        return whether the given section has the given option
47

48
    read(filenames)
49
        read and parse the list of named configuration files, given by
50
        name.  A single filename is also allowed.  Non-existing files
51
        are ignored.
52

53
    readfp(fp, filename=None)
54
        read and parse one configuration file, given as a file object.
55
        The filename defaults to fp.name; it is only used in error
56
        messages (if fp has no `name' attribute, the string `<???>' is used).
57

58
    get(section, option, raw=0, vars=None)
59
        return a string value for the named option.  All % interpolations are
60
        expanded in the return values, based on the defaults passed into the
61
        constructor and the DEFAULT section.  Additional substitutions may be
62
        provided using the `vars' argument, which must be a dictionary whose
63
        contents override any pre-existing defaults.
64

65
    getint(section, options)
66
        like get(), but convert value to an integer
67

68
    getfloat(section, options)
69
        like get(), but convert value to a float
70

71
    getboolean(section, options)
72
        like get(), but convert value to a boolean (currently defined as 0 or
73
        1, only)
74

75
    remove_section(section)
76
        remove the given file section and all its options
77

78
    remove_option(section, option)
79
        remove the given option from the given section
80

81
    set(section, option, value)
82
        set the given option
83

84
    write(fp)
85
        write the configuration state in .ini format
86
"""
87
88
import sys
89
import string
90
import re
91
92
__all__ = ["NoSectionError","DuplicateSectionError","NoOptionError",
93
           "InterpolationError","InterpolationDepthError","ParsingError",
94
           "MissingSectionHeaderError","ConfigParser",
95
           "MAX_INTERPOLATION_DEPTH"]
96
97
DEFAULTSECT = "DEFAULT"
98
99
MAX_INTERPOLATION_DEPTH = 10
100
101
102
103
# exception classes
104
class Error(Exception):
105
    def __init__(self, msg=''):
106
        self._msg = msg
107
        Exception.__init__(self, msg)
108
    def __repr__(self):
109
        return self._msg
110
    __str__ = __repr__
111
112
class NoSectionError(Error):
113
    def __init__(self, section):
114
        Error.__init__(self, 'No section: %s' % section)
115
        self.section = section
116
117
class DuplicateSectionError(Error):
118
    def __init__(self, section):
119
        Error.__init__(self, "Section %s already exists" % section)
120
        self.section = section
121
122
class NoOptionError(Error):
123
    def __init__(self, option, section):
124
        Error.__init__(self, "No option `%s' in section: %s" %
125
                       (option, section))
126
        self.option = option
127
        self.section = section
128
129
class InterpolationError(Error):
130
    def __init__(self, reference, option, section, rawval):
131
        Error.__init__(self,
132
                       "Bad value substitution:\n"
133
                       "\tsection: [%s]\n"
134
                       "\toption : %s\n"
135
                       "\tkey    : %s\n"
136
                       "\trawval : %s\n"
137
                       % (section, option, reference, rawval))
138
        self.reference = reference
139
        self.option = option
140
        self.section = section
141
142
class InterpolationDepthError(Error):
143
    def __init__(self, option, section, rawval):
144
        Error.__init__(self,
145
                       "Value interpolation too deeply recursive:\n"
146
                       "\tsection: [%s]\n"
147
                       "\toption : %s\n"
148
                       "\trawval : %s\n"
149
                       % (section, option, rawval))
150
        self.option = option
151
        self.section = section
152
153
class ParsingError(Error):
154
    def __init__(self, filename):
155
        Error.__init__(self, 'File contains parsing errors: %s' % filename)
156
        self.filename = filename
157
        self.errors = []
158
159
    def append(self, lineno, line):
160
        self.errors.append((lineno, line))
161
        self._msg = self._msg + '\n\t[line %2d]: %s' % (lineno, line)
162
163
class MissingSectionHeaderError(ParsingError):
164
    def __init__(self, filename, lineno, line):
165
        Error.__init__(
166
            self,
167
            'File contains no section headers.\nfile: %s, line: %d\n%s' %
168
            (filename, lineno, line))
169
        self.filename = filename
170
        self.lineno = lineno
171
        self.line = line
172
173
174
175
class ConfigParser:
176
    def __init__(self, defaults=None):
177
        self.__sections = {}
178
        if defaults is None:
179
            self.__defaults = {}
180
        else:
181
            self.__defaults = defaults
182
183
    def defaults(self):
184
        return self.__defaults
185
186
    def sections(self):
187
        """Return a list of section names, excluding [DEFAULT]"""
188
        # self.__sections will never have [DEFAULT] in it
189
        return self.__sections.keys()
190
191
    def add_section(self, section):
192
        """Create a new section in the configuration.
193

194
        Raise DuplicateSectionError if a section by the specified name
195
        already exists.
196
        """
197
        if self.__sections.has_key(section):
198
            raise DuplicateSectionError(section)
199
        self.__sections[section] = {}
200
201
    def has_section(self, section):
202
        """Indicate whether the named section is present in the configuration.
203

204
        The DEFAULT section is not acknowledged.
205
        """
206
        return section in self.sections()
207
208
    def options(self, section):
209
        """Return a list of option names for the given section name."""
210
        try:
211
            opts = self.__sections[section].copy()
212
        except KeyError:
213
            raise NoSectionError(section)
214
        opts.update(self.__defaults)
215
        if opts.has_key('__name__'):
216
            del opts['__name__']
217
        return opts.keys()
218
219
    def has_option(self, section, option):
220
        """Return whether the given section has the given option."""
221
        return option in self.options(section)
222
223
    def read(self, filenames):
224
        """Read and parse a filename or a list of filenames.
225

226
        Files that cannot be opened are silently ignored; this is
227
        designed so that you can specify a list of potential
228
        configuration file locations (e.g. current directory, user's
229
        home directory, systemwide directory), and all existing
230
        configuration files in the list will be read.  A single
231
        filename may also be given.
232
        """
233
        if type(filenames) in [type(''), type(u'')]:
234
            filenames = [filenames]
235
        for filename in filenames:
236
            try:
237
                fp = open(filename)
238
            except IOError:
239
                continue
240
            self.__read(fp, filename)
241
            fp.close()
242
243
    def readfp(self, fp, filename=None):
244
        """Like read() but the argument must be a file-like object.
245

246
        The `fp' argument must have a `readline' method.  Optional
247
        second argument is the `filename', which if not given, is
248
        taken from fp.name.  If fp has no `name' attribute, `<???>' is
249
        used.
250

251
        """
252
        if filename is None:
253
            try:
254
                filename = fp.name
255
            except AttributeError:
256
                filename = '<???>'
257
        self.__read(fp, filename)
258
259
    def get(self, section, option, raw=0, vars=None):
260
        """Get an option value for a given section.
261

262
        All % interpolations are expanded in the return values, based on the
263
        defaults passed into the constructor, unless the optional argument
264
        `raw' is true.  Additional substitutions may be provided using the
265
        `vars' argument, which must be a dictionary whose contents overrides
266
        any pre-existing defaults.
267

268
        The section DEFAULT is special.
269
        """
270
        try:
271
            sectdict = self.__sections[section].copy()
272
        except KeyError:
273
            if section == DEFAULTSECT:
274
                sectdict = {}
275
            else:
276
                raise NoSectionError(section)
277
        d = self.__defaults.copy()
278
        d.update(sectdict)
279
        # Update with the entry specific variables
280
        if vars:
281
            d.update(vars)
282
        option = self.optionxform(option)
283
        try:
284
            rawval = d[option]
285
        except KeyError:
286
            raise NoOptionError(option, section)
287
288
        if raw:
289
            return rawval
290
291
        # do the string interpolation
292
        value = rawval                  # Make it a pretty variable name
293
        depth = 0
294
        while depth < 10:               # Loop through this until it's done
295
            depth = depth + 1
296
            if value.find("%(") >= 0:
297
                try:
298
                    value = value % d
299
                except KeyError, key:
300
                    raise InterpolationError(key, option, section, rawval)
301
            else:
302
                break
303
        if value.find("%(") >= 0:
304
            raise InterpolationDepthError(option, section, rawval)
305
        return value
306
307
    def __get(self, section, conv, option):
308
        return conv(self.get(section, option))
309
310
    def getint(self, section, option):
311
        return self.__get(section, string.atoi, option)
312
313
    def getfloat(self, section, option):
314
        return self.__get(section, string.atof, option)
315
316
    def getboolean(self, section, option):
317
        v = self.get(section, option)
318
        val = int(v)
319
        if val not in (0, 1):
320
            raise ValueError, 'Not a boolean: %s' % v
321
        return val
322
323
    def optionxform(self, optionstr):
324
        return optionstr.lower()
325
326
    def has_option(self, section, option):
327
        """Check for the existence of a given option in a given section."""
328
        if not section or section == "DEFAULT":
329
            return self.__defaults.has_key(option)
330
        elif not self.has_section(section):
331
            return 0
332
        else:
333
            option = self.optionxform(option)
334
            return self.__sections[section].has_key(option)
335
336
    def set(self, section, option, value):
337
        """Set an option."""
338
        if not section or section == "DEFAULT":
339
            sectdict = self.__defaults
340
        else:
341
            try:
342
                sectdict = self.__sections[section]
343
            except KeyError:
344
                raise NoSectionError(section)
345
        option = self.optionxform(option)
346
        sectdict[option] = value
347
348
    def write(self, fp):
349
        """Write an .ini-format representation of the configuration state."""
350
        if self.__defaults:
351
            fp.write("[DEFAULT]\n")
352
            for (key, value) in self.__defaults.items():
353
                fp.write("%s = %s\n" % (key, value))
354
            fp.write("\n")
355
        for section in self.sections():
356
            fp.write("[" + section + "]\n")
357
            sectdict = self.__sections[section]
358
            for (key, value) in sectdict.items():
359
                if key == "__name__":
360
                    continue
361
                fp.write("%s = %s\n" % (key, value))
362
            fp.write("\n")
363
364
    def remove_option(self, section, option):
365
        """Remove an option."""
366
        if not section or section == "DEFAULT":
367
            sectdict = self.__defaults
368
        else:
369
            try:
370
                sectdict = self.__sections[section]
371
            except KeyError:
372
                raise NoSectionError(section)
373
        option = self.optionxform(option)
374
        existed = sectdict.has_key(option)
375
        if existed:
376
            del sectdict[option]
377
        return existed
378
379
    def remove_section(self, section):
380
        """Remove a file section."""
381
        if self.__sections.has_key(section):
382
            del self.__sections[section]
383
            return 1
384
        else:
385
            return 0
386
387
    #
388
    # Regular expressions for parsing section headers and options.  Note a
389
    # slight semantic change from the previous version, because of the use
390
    # of \w, _ is allowed in section header names.
391
    SECTCRE = re.compile(
392
        r'\['                                 # [
393
        r'(?P<header>[^]]+)'                  # very permissive!
394
        r'\]'                                 # ]
395
        )
396
    OPTCRE = re.compile(
397
        r'(?P<option>[]\-[\w_.*,(){}]+)'      # a lot of stuff found by IvL
398
        r'[ \t]*(?P<vi>[:=])[ \t]*'           # any number of space/tab,
399
                                              # followed by separator
400
                                              # (either : or =), followed
401
                                              # by any # space/tab
402
        r'(?P<value>.*)$'                     # everything up to eol
403
        )
404
405
    def __read(self, fp, fpname):
406
        """Parse a sectioned setup file.
407

408
        The sections in setup file contains a title line at the top,
409
        indicated by a name in square brackets (`[]'), plus key/value
410
        options lines, indicated by `name: value' format lines.
411
        Continuation are represented by an embedded newline then
412
        leading whitespace.  Blank lines, lines beginning with a '#',
413
        and just about everything else is ignored.
414
        """
415
        cursect = None                            # None, or a dictionary
416
        optname = None
417
        lineno = 0
418
        e = None                                  # None, or an exception
419
        while 1:
420
            line = fp.readline()
421
            if not line:
422
                break
423
            lineno = lineno + 1
424
            # comment or blank line?
425
            if line.strip() == '' or line[0] in '#;':
426
                continue
427
            if line.split()[0].lower() == 'rem' \
428
               and line[0] in "rR":      # no leading whitespace
429
                continue
430
            # continuation line?
431
            if line[0] in ' \t' and cursect is not None and optname:
432
                value = line.strip()
433
                if value:
434
                    k = self.optionxform(optname)
435
                    cursect[k] = "%s\n%s" % (cursect[k], value)
436
            # a section header or option header?
437
            else:
438
                # is it a section header?
439
                mo = self.SECTCRE.match(line)
440
                if mo:
441
                    sectname = mo.group('header')
442
                    if self.__sections.has_key(sectname):
443
                        cursect = self.__sections[sectname]
444
                    elif sectname == DEFAULTSECT:
445
                        cursect = self.__defaults
446
                    else:
447
                        cursect = {'__name__': sectname}
448
                        self.__sections[sectname] = cursect
449
                    # So sections can't start with a continuation line
450
                    optname = None
451
                # no section header in the file?
452
                elif cursect is None:
453
                    raise MissingSectionHeaderError(fpname, lineno, `line`)
454
                # an option line?
455
                else:
456
                    mo = self.OPTCRE.match(line)
457
                    if mo:
458
                        optname, vi, optval = mo.group('option', 'vi', 'value')
459
                        if vi in ('=', ':') and ';' in optval:
460
                            # ';' is a comment delimiter only if it follows
461
                            # a spacing character
462
                            pos = optval.find(';')
463
                            if pos and optval[pos-1] in string.whitespace:
464
                                optval = optval[:pos]
465
                        optval = optval.strip()
466
                        # allow empty values
467
                        if optval == '""':
468
                            optval = ''
469
                        cursect[self.optionxform(optname)] = optval
470
                    else:
471
                        # a non-fatal parsing error occurred.  set up the
472
                        # exception but keep going. the exception will be
473
                        # raised at the end of the file and will contain a
474
                        # list of all bogus lines
475
                        if not e:
476
                            e = ParsingError(fpname)
477
                        e.append(lineno, `line`)
478
        # if any parsing errors occurred, raise an exception
479
        if e:
480
            raise e