1+ """
2+ This is my own implementation of standard library ConfigParser module
3+ It parses .ini file and generates a configuration object
4+ """
5+ import re , collections
6+
7+ FORMAT_RE = r'.*%\([^\)]+\)[sd].*'
8+ SECTION_RE = r'\[([^\[\]]+)\]'
9+ OPTION_RE = r'(.*)=(.*)'
10+ COMMENT_RE = r'^;.*'
11+
12+ class InvalidConfig (Exception ):
13+ pass
14+
15+ def _is_format_str (s ):
16+ regex = re .compile (FORMAT_RE )
17+ return regex .match (s )
18+
19+ def _parse_config_file (f ):
20+ sections = {}
21+ current_section = None
22+ current_options = {}
23+
24+ section_re = re .compile (SECTION_RE )
25+ option_re = re .compile (OPTION_RE )
26+ comment_re = re .compile (COMMENT_RE )
27+
28+ for line in f :
29+ line = line .strip ()
30+
31+ if not line : continue
32+ if comment_re .match (line ): continue
33+
34+ mo = section_re .match (line )
35+ if mo :
36+ if current_section :
37+ sections [current_section ] = current_options
38+ current_section = mo .group (1 )
39+ current_options = {}
40+ else :
41+ mo1 = option_re .match (line )
42+ if mo1 :
43+ if not current_section :
44+ raise InvalidConfig ("Invalid config file" )
45+ key , value = mo1 .group (1 ).strip (), mo1 .group (2 ).strip ()
46+ current_options [key ] = value
47+ else :
48+ raise InvalidConfig ("Invalid config file" )
49+ if current_section :
50+ sections [current_section ] = current_options
51+ return sections
52+
53+ class ConfigParser (object ):
54+ def __init__ (self , defaults = None ):
55+ """
56+ create the parser and specify a dictionary of intrinsic defaults. The
57+ keys must be strings, the values must be appropriate for %()s string
58+ interpolation. Note that `__name__' is always an intrinsic default;
59+ its value is the section's name.
60+ """
61+ self ._defaults = defaults if defaults else {}
62+ self ._sections = {}
63+
64+
65+ def sections (self ):
66+ # return all the configuration section names
67+ return self ._sections .keys ()
68+
69+ def has_section (self , section ):
70+ return section in self ._sections
71+
72+ def has_option (self , section , option ):
73+ return self .has_section (section ) and option in self ._sections [section ]
74+
75+ def options (self , section ):
76+ if not self .has_section (section ):
77+ return []
78+ else :
79+ return self ._sections [section ].keys ()
80+
81+ def read (self , filenames ):
82+ """
83+ read and parse the list of named configuration files, given by
84+ name. A single filename is also allowed. Non-existing files
85+ are ignored. Return list of successfully read files.
86+ """
87+ if isinstance (filenames , basestring ):
88+ f = open (filenames , 'r' )
89+ self .readfp (f )
90+ elif isinstance (filenames , collections .Iterable ):
91+ for fname in filenames :
92+ try :
93+ f = open (fname , 'r' )
94+ self .readfp (f )
95+ except IOError :
96+ print "Fail to open file %s, ignored" % fname
97+ except InvalidConfig :
98+ print "Invalid config file %s, ignored" % fname
99+
100+ def readfp (self , fp , filename = None ):
101+ """
102+ read and parse one configuration file, given as a file object.
103+ The filename defaults to fp.name; it is only used in error
104+ messages (if fp has no `name' attribute, the string `<???>' is used).
105+ """
106+ secs = _parse_config_file (fp )
107+ self ._sections .update (secs )
108+
109+ def parse_item (self , section , key , val ):
110+ # Now support only 1 level of interpolation
111+ if not _is_format_str (val ):
112+ return val
113+ else :
114+ # first try default section
115+ try :
116+ newval = val % self ._defaults
117+ except KeyError :
118+ try :
119+ newval = val % self ._sections [section ]
120+ except KeyError :
121+ newval = val
122+ return newval
123+
124+ def get (self , section , option , raw = False , vars = None ):
125+ if not self .has_section (section ):
126+ return None
127+ sec = self ._sections [section ]
128+ if option not in sec :
129+ return None
130+ return self .parse_item (section , option , sec [option ])
131+
132+ def getint (self , section , option ):
133+ return int (self .get (section , option ))
134+
135+ def getfloat (self , section , option ):
136+ return float (self .get (section , option ))
137+
138+ def getboolean (self , section , option ):
139+ val = self .get (section , option ).strip ()
140+ if val .lower () in ["0" , "false" , "no" , "off" ]:
141+ return False
142+ elif val .lower () in ["1" , "true" , "yes" , "on" ]:
143+ return True
144+ else :
145+ raise ValueError ("Invalid boolean option" )
146+
147+ def items (self , section , raw = False , vars = None ):
148+ try :
149+ d = self ._sections [section ]
150+ except KeyError :
151+ d = {}
152+ d .update (self ._defaults )
153+ return d .items ()
154+
155+ def remove_section (self , section ):
156+ if self .has_section (section ):
157+ del self ._sections [section ]
158+
159+ def remove_option (self , section , option ):
160+ if self .has_option (section , option ):
161+ del self ._sections [section ][option ]
162+
163+ def set (self , section , option , value ):
164+ if self .has_section (section ):
165+ self ._sections [section ][option ] = value
166+
167+ def write (self , fp ):
168+ #write the configuration state in .ini format
169+ pass
0 commit comments