Revision: 141
Author: psoberoi
Date: Sat May 8 12:58:40 2010
Log: Accessing non-existing sections using the container notation
(i.e. cfg['foo']['bar']) will auto-create the sections. This
has always been the behavior for dotted access, but so far
container access used to raise a KeyError exception.
http://code.google.com/p/iniparse/source/detail?r=141
Modified:
/trunk/iniparse/compat.py
/trunk/iniparse/config.py
/trunk/iniparse/ini.py
/trunk/tests/test_ini.py
=======================================
--- /trunk/iniparse/compat.py Sun Feb 22 13:35:19 2009
+++ /trunk/iniparse/compat.py Sat May 8 12:58:40 2010
@@ -68,17 +68,13 @@
The DEFAULT section is not acknowledged.
"""
- try:
- self.data[section]
- return True
- except KeyError:
- return False
+ return (section in self.data)
def options(self, section):
"""Return a list of option names for the given section name."""
- try:
+ if section in self.data:
return list(self.data[section])
- except KeyError:
+ else:
raise NoSectionError(section)
def read(self, filenames):
@@ -119,19 +115,20 @@
raise NoSectionError(section)
if vars is not None and option in vars:
value = vars[option]
- try:
- sec = self.data[section]
+
+ sec = self.data[section]
+ if option in sec:
return sec._compat_get(option)
- except KeyError:
+ else:
raise NoOptionError(option, section)
def items(self, section):
- try:
+ if section in self.data:
ans = []
for opt in self.data[section]:
ans.append((opt, self.get(section, opt)))
return ans
- except KeyError:
+ else:
raise NoSectionError(section)
def getint(self, section, option):
@@ -151,21 +148,17 @@
def has_option(self, section, option):
"""Check for the existence of a given option in a given section."""
- try:
+ if section in self.data:
sec = self.data[section]
- except KeyError:
+ else:
raise NoSectionError(section)
- try:
- sec[option]
- return True
- except KeyError:
- return False
+ return (option in sec)
def set(self, section, option, value):
"""Set an option."""
- try:
+ if section in self.data:
self.data[section][option] = value
- except KeyError:
+ else:
raise NoSectionError(section)
def write(self, fp):
@@ -174,15 +167,14 @@
def remove_option(self, section, option):
"""Remove an option."""
- try:
+ if section in self.data:
sec = self.data[section]
- except KeyError:
+ else:
raise NoSectionError(section)
- try:
- sec[option]
+ if option in sec:
del sec[option]
return 1
- except KeyError:
+ else:
return 0
def remove_section(self, section):
=======================================
--- /trunk/iniparse/config.py Fri May 7 09:04:34 2010
+++ /trunk/iniparse/config.py Sat May 8 12:58:40 2010
@@ -17,7 +17,7 @@
# Methods that must be implemented by subclasses
- def __getitem__(self, key):
+ def _getitem(self, key):
return NotImplementedError(key)
def __setitem__(self, key, value):
@@ -32,7 +32,15 @@
def _new_namespace(self, name):
raise NotImplementedError(name)
- # Machinery for converting dotted access into contained access
+ def __contains__(self, key):
+ try:
+ self._getitem(key)
+ except KeyError:
+ return False
+ return True
+
+ # Machinery for converting dotted access into container access,
+ # and automatically creating new sections/namespaces.
#
# To distinguish between accesses of class members and namespace
# keys, we first call object.__getattribute__(). If that succeeds,
@@ -43,9 +51,15 @@
# not just in the __init__() function. See BasicNamespace for
# an example.
+ def __getitem__(self, key):
+ try:
+ return self._getitem(key)
+ except KeyError:
+ return Undefined(key, self)
+
def __getattr__(self, name):
try:
- return self.__getitem__(name)
+ return self._getitem(name)
except KeyError:
if name.startswith('__') and name.endswith('__'):
raise AttributeError
@@ -65,10 +79,10 @@
except AttributeError:
self.__delitem__(name)
- # During unpickling, __getattr__/__getitem__ raise exceptions since
- # the data dicts have not been initialized yet. So, the attribute
- # lookup for __setstate__ gets a non-AttributeError exception. Thus
- # we need to define it explicitly.
+ # During unpickling, Python checks if the class has a __setstate__
+ # method. But, the data dicts have not been initialised yet, which
+ # leads to _getitem and hence __getattr__ raising an exception. So
+ # we explicitly impement default __setstate__ behavior.
def __setstate__(self, state):
self.__dict__.update(state)
@@ -88,6 +102,10 @@
obj = self.namespace._new_namespace(
self.name)
obj[name] = value
+ def __setitem__(self, name, value):
+ obj = self.namespace._new_namespace(
self.name)
+ obj[name] = value
+
# ---- Basic implementation of a ConfigNamespace
@@ -167,7 +185,7 @@
def __init__(self):
self._data = {}
- def __getitem__(self, key):
+ def _getitem(self, key):
return self._data[key]
def __setitem__(self, key, value):
@@ -218,11 +236,11 @@
name_components = name.split('.')
ns = self
for n in name_components[:-1]:
- try:
+ if n in ns:
ns = ns[n]
if not isinstance(ns, ConfigNamespace):
raise TypeError('value-namespace conflict', n)
- except KeyError:
+ else:
ns = ns._new_namespace(n)
ns[name_components[-1]] = value
@@ -262,11 +280,11 @@
for name in source:
value = source[name]
if isinstance(value, ConfigNamespace):
- try:
+ if name in target:
myns = target[name]
if not isinstance(myns, ConfigNamespace):
raise TypeError('value-namespace conflict')
- except KeyError:
+ else:
myns = target._new_namespace(name)
update_config(myns, value)
else:
=======================================
--- /trunk/iniparse/ini.py Sat May 8 00:00:44 2010
+++ /trunk/iniparse/ini.py Sat May 8 12:58:40 2010
@@ -351,7 +351,7 @@
value = re.sub('\n+', '\n', value)
return value
- def __getitem__(self, key):
+ def _getitem(self, key):
if key == '__name__':
return self._lines[-1].name
if self._optionxform: key = self._optionxform(key)
@@ -473,7 +473,7 @@
_optionxform = _make_xform_property('_optionxform', 'optionxform')
_sectionxform = _make_xform_property('_sectionxform', 'optionxform')
- def __getitem__(self, key):
+ def _getitem(self, key):
if key == DEFAULTSECT:
return self._defaults
if self._sectionxform: key = self._sectionxform(key)
=======================================
--- /trunk/tests/test_ini.py Sat Apr 17 11:30:31 2010
+++ /trunk/tests/test_ini.py Sat May 8 12:58:40 2010
@@ -223,8 +223,14 @@
p = ini.INIConfig(sio)
p.new1.created = 1
setattr(getattr(p, 'new2'), 'created', 1)
+ p.new3['created'] = 1
+ p['new4'].created = 1
+ p['new5']['created'] = 1
self.assertEqual(p.new1.created, 1)
self.assertEqual(p.new2.created, 1)
+ self.assertEqual(p.new3.created, 1)
+ self.assertEqual(p.new4.created, 1)
+ self.assertEqual(p.new5.created, 1)
def test_order(self):
sio = StringIO(self.s1)
--
To post to this group, send email to
iniparse...@googlegroups.com
To unsubscribe from this group, send email to
iniparse-commi...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/iniparse-commits?hl=en