| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -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: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -27,3 +27,8 @@ | |||
| 27 | 27 | [branch "mainline_performance"] | |
| 28 | 28 | remote = mainline | |
| 29 | 29 | merge = refs/heads/master | |
| 30 | + [filter "indent"] | ||
| 31 | + clean = indent | ||
| 32 | + smudge = cat | ||
| 33 | + # A vauleless option | ||
| 34 | + required | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -77,18 +77,22 @@ def test_base(self): | |||
| 77 | 77 | assert r_config._is_initialized == False | |
| 78 | 78 | for section in r_config.sections(): | |
| 79 | 79 | num_sections += 1 | |
| 80 | - for option in r_config.options(section): | ||
| 81 | - num_options += 1 | ||
| 82 | - val = r_config.get(section, option) | ||
| 83 | - val_typed = r_config.get_value(section, option) | ||
| 84 | - assert isinstance(val_typed, (bool, long, float, basestring)) | ||
| 85 | - assert val | ||
| 86 | - assert "\n" not in option | ||
| 87 | - assert "\n" not in val | ||
| 88 | - | ||
| 89 | - # writing must fail | ||
| 90 | - self.failUnlessRaises(IOError, r_config.set, section, option, None) | ||
| 91 | - self.failUnlessRaises(IOError, r_config.remove_option, section, option) | ||
| 80 | + if section != 'filter "indent"': | ||
| 81 | + for option in r_config.options(section): | ||
| 82 | + num_options += 1 | ||
| 83 | + val = r_config.get(section, option) | ||
| 84 | + val_typed = r_config.get_value(section, option) | ||
| 85 | + assert isinstance(val_typed, (bool, long, float, basestring)) | ||
| 86 | + assert val | ||
| 87 | + assert "\n" not in option | ||
| 88 | + assert "\n" not in val | ||
| 89 | + | ||
| 90 | + # writing must fail | ||
| 91 | + self.failUnlessRaises(IOError, r_config.set, section, option, None) | ||
| 92 | + self.failUnlessRaises(IOError, r_config.remove_option, section, option) | ||
| 93 | + else: | ||
| 94 | + val = r_config.get(section, 'required') | ||
| 95 | + assert val is None | ||
| 92 | 96 | # END for each option | |
| 93 | 97 | self.failUnlessRaises(IOError, r_config.remove_section, section) | |
| 94 | 98 | # END for each section | |
| Back | FazBrowse Home | New Git URL |
0 commit comments