@@ -131,19 +131,20 @@ class GitConfigParser(cp.RawConfigParser, object):
131
131
132
132
OPTCRE = re .compile (
133
133
r'\s*(?P<option>[^:=\s][^:=]*)' # very permissive, incuding leading whitespace
134
- r'\s*(?P<vi>[:=])\s*' # any number of space/tab,
135
- # followed by separator
136
- # (either : or =), followed
137
- # by any # space/tab
138
- r'(?P<value>.*)$' # everything up to eol
139
- )
134
+ r'\s*(?:' # any number of space/tab,
135
+ r'(?P<vi>[:=])\s*' # optionally followed by
136
+ # separator (either : or
137
+ # =), followed by any #
138
+ # space/tab
139
+ r'(?P<value>.*))?$' # everything up to eol
140
+ )
140
141
141
142
# list of RawConfigParser methods able to change the instance
142
143
_mutating_methods_ = ("add_section" , "remove_section" , "remove_option" , "set" )
143
144
__slots__ = ("_sections" , "_defaults" , "_file_or_files" , "_read_only" , "_is_initialized" , '_lock' )
144
145
145
146
def __init__ (self , file_or_files , read_only = True ):
146
- """Initialize a configuration reader to read the given file_or_files and to
147
+ """Initialize a configuration reader to read the given file_or_files and to
147
148
possibly allow changes to it by setting read_only False
148
149
149
150
:param file_or_files:
@@ -198,10 +199,10 @@ def optionxform(self, optionstr):
198
199
return optionstr
199
200
200
201
def _read (self , fp , fpname ):
201
- """A direct copy of the py2.4 version of the super class's _read method
202
+ """A direct copy of the py2.7 version of the super class's _read method
202
203
to assure it uses ordered dicts. Had to change one line to make it work.
203
204
204
- Future versions have this fixed, but in fact its quite embarassing for the
205
+ Future versions have this fixed, but in fact its quite embarassing for the
205
206
guys not to have done it right in the first place !
206
207
207
208
Removed big comments to make it more compact.
@@ -222,6 +223,7 @@ def _read(self, fp, fpname):
222
223
if line .split (None , 1 )[0 ].lower () == 'rem' and line [0 ] in "rR" :
223
224
# no leading whitespace
224
225
continue
226
+ # a section header or option header?
225
227
else :
226
228
# is it a section header?
227
229
mo = self .SECTCRE .match (line .strip ())
@@ -245,43 +247,48 @@ def _read(self, fp, fpname):
245
247
mo = self .OPTCRE .match (line )
246
248
if mo :
247
249
optname , vi , optval = mo .group ('option' , 'vi' , 'value' )
248
- if vi in ('=' , ':' ) and ';' in optval :
249
- pos = optval .find (';' )
250
- if pos != - 1 and optval [pos - 1 ].isspace ():
251
- optval = optval [:pos ]
252
- optval = optval .strip ()
253
-
254
- # Remove paired unescaped-quotes
255
- unquoted_optval = ''
256
- escaped = False
257
- in_quote = False
258
- for c in optval :
259
- if not escaped and c == '"' :
260
- in_quote = not in_quote
261
- else :
262
- escaped = (c == '\\ ' ) and not escaped
263
- unquoted_optval += c
264
-
265
- if in_quote :
266
- if not e :
267
- e = cp .ParsingError (fpname )
268
- e .append (lineno , repr (line ))
269
-
270
- optval = unquoted_optval
271
-
272
- optval = optval .replace ('\\ \\ ' , '\\ ' ) # Unescape backslashes
273
- optval = optval .replace (r'\"' , '"' ) # Unescape quotes
274
-
275
250
optname = self .optionxform (optname .rstrip ())
276
- cursect [optname ] = optval
251
+ if optval is not None :
252
+ if vi in ('=' , ':' ) and ';' in optval :
253
+ # ';' is a comment delimiter only if it follows
254
+ # a spacing character
255
+ pos = optval .find (';' )
256
+ if pos != - 1 and optval [pos - 1 ].isspace ():
257
+ optval = optval [:pos ]
258
+ optval = optval .strip ()
259
+ # allow empty values
260
+ if optval == '""' :
261
+ optval = ''
262
+ # Remove paired unescaped-quotes
263
+ unquoted_optval = ''
264
+ escaped = False
265
+ in_quote = False
266
+ for c in optval :
267
+ if not escaped and c == '"' :
268
+ in_quote = not in_quote
269
+ else :
270
+ escaped = (c == '\\ ' ) and not escaped
271
+ unquoted_optval += c
272
+ if in_quote :
273
+ if not e :
274
+ e = cp .ParsingError (fpname )
275
+ e .append (lineno , repr (line ))
276
+
277
+ optval = unquoted_optval
278
+ optval = optval .replace ('\\ \\ ' , '\\ ' ) # Unescape backslashes
279
+ optval = optval .replace (r'\"' , '"' ) # Unescape quotes
280
+ cursect [optname ] = optval
281
+ else :
282
+ # valueless option handling
283
+ cursect [optname ] = optval
277
284
else :
285
+ # a non-fatal parsing error occurred. set up the
286
+ # exception but keep going. the exception will be
287
+ # raised at the end of the file and will contain a
288
+ # list of all bogus lines
278
289
if not e :
279
290
e = cp .ParsingError (fpname )
280
291
e .append (lineno , repr (line ))
281
- # END
282
- # END ?
283
- # END ?
284
- # END while reading
285
292
# if any parsing errors occurred, raise an exception
286
293
if e :
287
294
raise e
@@ -398,7 +405,7 @@ def get_value(self, section, option, default=None):
398
405
:param default:
399
406
If not None, the given default value will be returned in case
400
407
the option did not exist
401
- :return: a properly typed value, either int, float or string
408
+ :return: a properly typed value, either int, bool, float, string or None
402
409
403
410
:raise TypeError: in case the value could not be understood
404
411
Otherwise the exceptions known to the ConfigParser will be raised."""
@@ -409,6 +416,9 @@ def get_value(self, section, option, default=None):
409
416
return default
410
417
raise
411
418
419
+ if valuestr is None :
420
+ return valuestr
421
+
412
422
types = (long , float )
413
423
for numtype in types :
414
424
try :
0 commit comments