summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/ConfigParser.py130
1 files changed, 90 insertions, 40 deletions
diff --git a/Lib/ConfigParser.py b/Lib/ConfigParser.py
index 957222c..f22306a 100644
--- a/Lib/ConfigParser.py
+++ b/Lib/ConfigParser.py
@@ -2,10 +2,11 @@
A setup file consists of sections, lead by a "[section]" header,
and followed by "name: value" entries, with continuations and such in
-the style of rfc822.
+the style of RFC 822.
+
+The option values can contain format strings which refer to other values in
+the same section, or values in a special [DEFAULT] section.
-The option values can contain format strings which refer to other
-values in the same section, or values in a special [DEFAULT] section.
For example:
something: %(dir)s/whatever
@@ -55,14 +56,7 @@ ConfigParser -- responsible for for parsing a list of
import sys
import string
-import regex
-from types import ListType
-
-
-SECTHEAD_RE = "^\[\([-A-Za-z0-9]*\)\][" + string.whitespace + "]*$"
-secthead_cre = regex.compile(SECTHEAD_RE)
-OPTION_RE = "^\([-A-Za-z0-9.]+\)\(:\|[" + string.whitespace + "]*=\)\(.*\)$"
-option_cre = regex.compile(OPTION_RE)
+import re
DEFAULTSECT = "DEFAULT"
@@ -71,9 +65,9 @@ DEFAULTSECT = "DEFAULT"
# exception classes
class Error:
def __init__(self, msg=''):
- self.__msg = msg
+ self._msg = msg
def __repr__(self):
- return self.__msg
+ return self._msg
class NoSectionError(Error):
def __init__(self, section):
@@ -101,6 +95,26 @@ class InterpolationError(Error):
self.option = option
self.section = section
+class MissingSectionHeaderError(Error):
+ def __init__(self, filename, lineno, line):
+ Error.__init__(
+ self,
+ 'File contains no section headers.\nfile: %s, line: %d\n%s' %
+ (filename, lineno, line))
+ self.filename = filename
+ self.lineno = lineno
+ self.line = line
+
+class ParsingError(Error):
+ def __init__(self, filename):
+ Error.__init__(self, 'File contains parsing errors: %s' % filename)
+ self.filename = filename
+ self.errors = []
+
+ def append(self, lineno, line):
+ self.errors.append((lineno, line))
+ self._msg = self._msg + '\n\t[line %2d]: %s' % (lineno, line)
+
class ConfigParser:
@@ -159,7 +173,8 @@ class ConfigParser:
"""Get an option value for a given section.
All % interpolations are expanded in the return values, based
- on the defaults passed into the constructor.
+ on the defaults passed into the constructor, unless the optional
+ argument `raw' is true.
The section DEFAULT is special.
"""
@@ -201,6 +216,24 @@ class ConfigParser:
raise ValueError, 'Not a boolean: %s' % v
return val
+ #
+ # Regular expressions for parsing section headers and options. Note a
+ # slight semantic change from the previous version, because of the use
+ # of \w, _ is allowed in section header names.
+ __SECTCRE = re.compile(
+ r'\[' # [
+ r'(?P<header>[-\w]+)' # `-', `_' or any alphanum
+ r'\]' # ]
+ )
+ __OPTCRE = re.compile(
+ r'(?P<option>[-.\w]+)' # - . _ alphanum
+ r'[ \t]*[:=][ \t]*' # any number of space/tab,
+ # followed by separator
+ # (either : or =), followed
+ # by any # space/tab
+ r'(?P<value>.*)$' # everything up to eol
+ )
+
def __read(self, fp):
"""Parse a sectioned setup file.
@@ -211,9 +244,10 @@ class ConfigParser:
leading whitespace. Blank lines, lines beginning with a '#',
and just about everything else is ignored.
"""
- cursect = None # None, or a dictionary
+ cursect = None # None, or a dictionary
optname = None
lineno = 0
+ e = None # None, or an exception
while 1:
line = fp.readline()
if not line:
@@ -226,31 +260,47 @@ class ConfigParser:
and line[0] == "r": # no leading whitespace
continue
# continuation line?
- if line[0] in ' \t' and cursect <> None and optname:
+ if line[0] in ' \t' and cursect is not None and optname:
value = string.strip(line)
if value:
- cursect = cursect[optname] + '\n ' + value
- # a section header?
- elif secthead_cre.match(line) >= 0:
- sectname = secthead_cre.group(1)
- if self.__sections.has_key(sectname):
- cursect = self.__sections[sectname]
- elif sectname == DEFAULTSECT:
- cursect = self.__defaults
- else:
- cursect = {'name': sectname}
- self.__sections[sectname] = cursect
- # So sections can't start with a continuation line.
- optname = None
- # an option line?
- elif option_cre.match(line) >= 0:
- optname, optval = option_cre.group(1, 3)
- optname = string.lower(optname)
- optval = string.strip(optval)
- # allow empty values
- if optval == '""':
- optval = ''
- cursect[optname] = optval
- # an error
+ cursect[optname] = cursect[optname] + '\n ' + value
+ # a section header or option header?
else:
- print 'Error in %s at %d: %s', (fp.name, lineno, `line`)
+ # is it a section header?
+ mo = self.__SECTCRE.match(line)
+ if mo:
+ sectname = mo.group('header')
+ if self.__sections.has_key(sectname):
+ cursect = self.__sections[sectname]
+ elif sectname == DEFAULTSECT:
+ cursect = self.__defaults
+ else:
+ cursect = {}
+ self.__sections[sectname] = cursect
+ # So sections can't start with a continuation line
+ optname = None
+ # no section header in the file?
+ elif cursect is None:
+ raise MissingSectionHeaderError(fp.name, lineno, `line`)
+ # an option line?
+ else:
+ mo = self.__OPTCRE.match(line)
+ if mo:
+ optname, optval = mo.group('option', 'value')
+ optname = string.lower(optname)
+ optval = string.strip(optval)
+ # allow empty values
+ if optval == '""':
+ optval = ''
+ cursect[optname] = optval
+ else:
+ # a non-fatal parsing error occurred. set up the
+ # exception but keep going. the exception will be
+ # raised at the end of the file and will contain a
+ # list of all bogus lines
+ if not e:
+ e = ParsingError(fp.name)
+ e.append(lineno, `line`)
+ # if any parsing errors occurred, raise an exception
+ if e:
+ raise e