summaryrefslogtreecommitdiff
path: root/iniparse
diff options
context:
space:
mode:
authorLudovico Cavedon <cavedon@debian.org>2010-06-12 16:34:16 -0700
committerLudovico Cavedon <cavedon@debian.org>2010-06-12 16:34:16 -0700
commitb58ade97bde0f26271ebbccf6959bfc5a30a88d2 (patch)
tree3d296c03823ea4806febf3d0d9becb8a90e57671 /iniparse
parent60b2e5ebf0b074436aaec91409d9863d015b9a73 (diff)
Imported Upstream version 0.4
Diffstat (limited to 'iniparse')
-rw-r--r--iniparse/__init__.py3
-rw-r--r--iniparse/compat.py44
-rw-r--r--iniparse/config.py43
-rw-r--r--iniparse/ini.py49
-rw-r--r--iniparse/utils.py47
5 files changed, 101 insertions, 85 deletions
diff --git a/iniparse/__init__.py b/iniparse/__init__.py
index 1a267e6..8de756f 100644
--- a/iniparse/__init__.py
+++ b/iniparse/__init__.py
@@ -3,9 +3,10 @@
# Copyright (c) 2007 Tim Lauridsen <tla@rasmil.dk>
# All Rights Reserved. See LICENSE-PSF & LICENSE for details.
-from ini import INIConfig, tidy, change_comment_syntax
+from ini import INIConfig, change_comment_syntax
from config import BasicConfig, ConfigNamespace
from compat import RawConfigParser, ConfigParser, SafeConfigParser
+from utils import tidy
from ConfigParser import DuplicateSectionError, \
NoSectionError, NoOptionError, \
diff --git a/iniparse/compat.py b/iniparse/compat.py
index 3de6148..db89ed8 100644
--- a/iniparse/compat.py
+++ b/iniparse/compat.py
@@ -68,17 +68,13 @@ class RawConfigParser(object):
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 @@ class RawConfigParser(object):
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 @@ class RawConfigParser(object):
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 @@ class RawConfigParser(object):
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):
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:
diff --git a/iniparse/ini.py b/iniparse/ini.py
index f0e7ec2..408354d 100644
--- a/iniparse/ini.py
+++ b/iniparse/ini.py
@@ -45,7 +45,6 @@ import re
from ConfigParser import DEFAULTSECT, ParsingError, MissingSectionHeaderError
import config
-import compat
class LineType(object):
line = None
@@ -352,7 +351,7 @@ class INISection(config.ConfigNamespace):
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)
@@ -474,7 +473,7 @@ class INIConfig(config.ConfigNamespace):
_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)
@@ -642,47 +641,3 @@ class INIConfig(config.ConfigNamespace):
raise exc
-def tidy(cfg):
- """Clean up blank lines.
-
- This functions makes the configuration look clean and
- handwritten - consecutive empty lines and empty lines at
- the start of the file are removed, and one is guaranteed
- to be at the end of the file.
- """
-
- if isinstance(cfg, compat.RawConfigParser):
- cfg = cfg.data
- cont = cfg._data.contents
- i = 1
- while i < len(cont):
- if isinstance(cont[i], LineContainer):
- tidy_section(cont[i])
- i += 1
- elif (isinstance(cont[i-1], EmptyLine) and
- isinstance(cont[i], EmptyLine)):
- del cont[i]
- else:
- i += 1
-
- # Remove empty first line
- if cont and isinstance(cont[0], EmptyLine):
- del cont[0]
-
- # Ensure a last line
- if cont and not isinstance(cont[-1], EmptyLine):
- cont.append(EmptyLine())
-
-def tidy_section(lc):
- cont = lc.contents
- i = 1
- while i < len(cont):
- if (isinstance(cont[i-1], EmptyLine) and
- isinstance(cont[i], EmptyLine)):
- del cont[i]
- else:
- i += 1
-
- # Remove empty first line
- if len(cont) > 1 and isinstance(cont[1], EmptyLine):
- del cont[1]
diff --git a/iniparse/utils.py b/iniparse/utils.py
new file mode 100644
index 0000000..829fc28
--- /dev/null
+++ b/iniparse/utils.py
@@ -0,0 +1,47 @@
+import compat
+from ini import LineContainer, EmptyLine
+
+def tidy(cfg):
+ """Clean up blank lines.
+
+ This functions makes the configuration look clean and
+ handwritten - consecutive empty lines and empty lines at
+ the start of the file are removed, and one is guaranteed
+ to be at the end of the file.
+ """
+
+ if isinstance(cfg, compat.RawConfigParser):
+ cfg = cfg.data
+ cont = cfg._data.contents
+ i = 1
+ while i < len(cont):
+ if isinstance(cont[i], LineContainer):
+ tidy_section(cont[i])
+ i += 1
+ elif (isinstance(cont[i-1], EmptyLine) and
+ isinstance(cont[i], EmptyLine)):
+ del cont[i]
+ else:
+ i += 1
+
+ # Remove empty first line
+ if cont and isinstance(cont[0], EmptyLine):
+ del cont[0]
+
+ # Ensure a last line
+ if cont and not isinstance(cont[-1], EmptyLine):
+ cont.append(EmptyLine())
+
+def tidy_section(lc):
+ cont = lc.contents
+ i = 1
+ while i < len(cont):
+ if (isinstance(cont[i-1], EmptyLine) and
+ isinstance(cont[i], EmptyLine)):
+ del cont[i]
+ else:
+ i += 1
+
+ # Remove empty first line
+ if len(cont) > 1 and isinstance(cont[1], EmptyLine):
+ del cont[1]