vrumger/ini-parser

ini-parser cannot handle empty keys

Closed this issue · 5 comments

providing a missing key (such as "Foo" in the following example):

ini.parse('[Section]\nFoo = \nBar = Baz\n')

will cause an IndexError:

In [4]: ini.parse('[Section]\nFoo = \nBar = Baz\n')
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-4-f5daad03ff17> in <module>
----> 1 ini.parse('[Section]\nFoo = \nBar = Baz\n')

~/open_source/ini-parser/ini/__init__.py in decode(string)
     78             continue
     79         key = unsafe(match[2])
---> 80         value = _parse_value(unsafe(match[4])) if match[3] else True
     81         if value in ('true', 'True'):
     82             value = True

~/open_source/ini-parser/ini/__init__.py in unsafe(val)
    140 def unsafe(val):
    141     val = (val or '').strip()
--> 142     if _is_quoted(val):
    143         # remove the single quotes before calling JSON.parse
    144         if val[0] == "'":

~/open_source/ini-parser/ini/__init__.py in _is_quoted(val)
    125 
    126 def _is_quoted(val):
--> 127     return (val[0] == '"' and val[-1] == '"') or (val[0] == "'" and val[-1] == "'")
    128 
    129 

IndexError: string index out of range

since it's sometimes desirable to explicitly fail and in other times it's desirable to have a default value (see the discussion regarding ConfigParser on SO), IMO decode() should define a new keyword parameter on_empty_key to be implemented as followed:

def decode(string, on_empty_key = object):
...
[__init__.py:80] if match[4].strip():
[__init__.py:81]     value = _parse_value(unsafe(match[4])) if match[3] else True
[__init__.py:82] elif on_empty_key == object:
[__init__.py:83]     raise ValueError(match[2].strip())
[__init__.py:84] else:
[__init__.py:85]     value = on_empty_key

with the proposed fix:

In [1]: import ini

In [2]: ini.parse('[Section]\nFoo = \nBar = Baz\n', on_empty_key=None)
Out[2]: {'Section': {'Foo': None, 'Bar': 'Baz'}}

In [3]: ini.parse('[Section]\nFoo = \nBar = Baz\n')
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-3-f5daad03ff17> in <module>
----> 1 ini.parse('[Section]\nFoo = \nBar = Baz\n')

~/open_source/ini-parser/ini/__init__.py in decode(string, on_empty_key)
     84             value = _parse_value(unsafe(match[4])) if match[3] else True
     85         elif on_empty_key == EMPTY_KEY_SENTINEL:
---> 86             raise ValueError(key)
     87         else:
     88             value = on_empty_key

ValueError: Foo

In [4]: 

I don't see why this is necessary. Why would you have an empty key?

hi andrew,
a quick search on google found this ini example showing an ini with an empty value.

generally speaking, I opted to use ini-parser over ConfigParser because of its simplicity, but not supporting empty values is a major drawback when comparing the two (since I need it to parse arbitrary ini files the user providers). while not part of the official format, many parsers allow such flexibility.

finally, since the default behavior (raising an exception) is kept (in a more user friendly manner IMO), I see no reason not to include this feature.

Hmm, thanks for the info. I'll review the PR later :)

Closed in #2.