diff options
Diffstat (limited to 'iniparse/config.py')
-rw-r--r-- | iniparse/config.py | 43 |
1 files changed, 32 insertions, 11 deletions
diff --git a/iniparse/config.py b/iniparse/config.py index 508dac2..5cfa2ea 100644 --- a/iniparse/config.py +++ b/iniparse/config.py @@ -17,7 +17,7 @@ class ConfigNamespace(object): # 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 @@ class ConfigNamespace(object): 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,10 +51,18 @@ class ConfigNamespace(object): # 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 return Undefined(name, self) def __setattr__(self, name, value): @@ -63,9 +79,10 @@ class ConfigNamespace(object): except AttributeError: self.__delitem__(name) - def __getstate__(self): - return self.__dict__ - + # 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) @@ -85,6 +102,10 @@ class Undefined(object): 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 @@ -164,7 +185,7 @@ class BasicConfig(ConfigNamespace): def __init__(self): self._data = {} - def __getitem__(self, key): + def _getitem(self, key): return self._data[key] def __setitem__(self, key, value): @@ -215,11 +236,11 @@ class BasicConfig(ConfigNamespace): 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 @@ -259,11 +280,11 @@ def update_config(target, source): 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: |