From 76d4171c2540f8de83b493750755a01dae7ced61 Mon Sep 17 00:00:00 2001 From: Peter Novotny Date: Tue, 16 May 2017 20:40:38 +0200 Subject: [PATCH] Added possibility to handle files with duplicate keys, default behavior kept --- docs/configobj.html | 13 +++++++++++-- src/configobj/__init__.py | 27 ++++++++++++++++++++------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/docs/configobj.html b/docs/configobj.html index 1cb1abe..16dc1ff 100644 --- a/docs/configobj.html +++ b/docs/configobj.html @@ -409,7 +409,7 @@

5   ConfigObj specificati interpolation=True, raise_errors=False, list_values=True, create_empty=False, file_error=False, stringify=True, indent_type=None, default_encoding=None, unrepr=False, - write_empty_values=False, _inspec=False) + write_empty_values=False, _inspec=False, duplicate_values=DUPLICATE_VALUES_THROW_ERROR)

Many of the keyword arguments are available as attributes after the config file has been parsed.

@@ -586,6 +586,14 @@

5   ConfigObj specificati for this argument as well as list_values=False.

+
  • 'duplicate_values': DUPLICATE_VALUES_THROW_ERROR

    +
    +

    Used internally by ConfigObj when handling duplicate keys within config file. Default value is DUPLICATE_VALUES_THROW_ERROR which +raises exception. To allow processing files with duplicate keys use one of configuration values +DUPLICATE_VALUES_FIRST or DUPLICATE_VALUES_LAST where only the +first or last (respectivelly) occurence of the duplicated key will be taken into account.

    +
    +
  • 5.1   Methods

    @@ -1541,7 +1549,8 @@

    8   Exceptions

  • DuplicateError

    -

    The keyword or section specified already exists.

    +

    The keyword or section specified already exists. Raising of this exception can be supressed by setting +duplicate_values.

  • ConfigspecError

    diff --git a/src/configobj/__init__.py b/src/configobj/__init__.py index 3f6eac0..15510d1 100644 --- a/src/configobj/__init__.py +++ b/src/configobj/__init__.py @@ -110,6 +110,9 @@ def match_utf8(encoding): DEFAULT_INTERPOLATION = 'configparser' DEFAULT_INDENT_TYPE = ' ' MAX_INTERPOL_DEPTH = 10 +DUPLICATE_VALUES_THROW_ERROR = 0 +DUPLICATE_VALUES_FIRST = 1 +DUPLICATE_VALUES_LAST = 2 OPTION_DEFAULTS = { 'interpolation': True, @@ -125,6 +128,7 @@ def match_utf8(encoding): 'default_encoding': None, 'unrepr': False, 'write_empty_values': False, + 'duplicate_values' : DUPLICATE_VALUES_THROW_ERROR, } # this could be replaced if six is used for compatibility, or there are no @@ -1145,7 +1149,7 @@ def __init__(self, infile=None, options=None, configspec=None, encoding=None, interpolation=True, raise_errors=False, list_values=True, create_empty=False, file_error=False, stringify=True, indent_type=None, default_encoding=None, unrepr=False, - write_empty_values=False, _inspec=False): + write_empty_values=False, _inspec=False, duplicate_values=DUPLICATE_VALUES_THROW_ERROR): """ Parse a config file or create a config file object. @@ -1167,7 +1171,7 @@ def __init__(self, infile=None, options=None, configspec=None, encoding=None, 'create_empty': create_empty, 'file_error': file_error, 'stringify': stringify, 'indent_type': indent_type, 'default_encoding': default_encoding, 'unrepr': unrepr, - 'write_empty_values': write_empty_values} + 'write_empty_values': write_empty_values, 'duplicate_values': duplicate_values} if options is None: options = _options @@ -1315,6 +1319,7 @@ def _initialise(self, options=None): self.indent_type = options['indent_type'] self.encoding = options['encoding'] self.default_encoding = options['default_encoding'] + self.duplicate_values = options['duplicate_values'] self.BOM = False self.newlines = None self.write_empty_values = options['write_empty_values'] @@ -1655,11 +1660,19 @@ def _parse(self, infile): # key = self._unquote(key) if key in this_section: - self._handle_error( - 'Duplicate keyword name', - DuplicateError, infile, cur_index) - continue - # add the key. + if self.duplicate_values == DUPLICATE_VALUES_THROW_ERROR : + self._handle_error( + 'Duplicate keyword name', + DuplicateError, infile, cur_index) + continue + if self.duplicate_values == DUPLICATE_VALUES_FIRST : + continue + if self.duplicate_values == DUPLICATE_VALUES_LAST : + this_section.__setitem__(key, value, unrepr=True) + this_section.inline_comments[key] = comment + this_section.comments[key] = comment_list + continue + # add the key. # we set unrepr because if we have got this far we will never # be creating a new section this_section.__setitem__(key, value, unrepr=True)