diff mixconfig/ini.py @ 2:9981a68040b6

An INI-style configuration file parser
author Franz Glasner <f.glasner@feldmann-mg.com>
date Tue, 08 Mar 2016 15:40:37 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mixconfig/ini.py	Tue Mar 08 15:40:37 2016 +0100
@@ -0,0 +1,93 @@
+# -*- coding: utf-8 -*-
+
+from __future__ import division, absolute_import, print_function
+
+import sys
+import os
+import io
+import locale
+try:
+    from configparser import SafeConfigParser, NoSectionError, NoOptionError
+except ImportError:
+    from ConfigParser import SafeConfigParser, NoSectionError, NoOptionError
+
+from .compat import PY2
+
+
+__all__ = ["INIConfigParser", "NoSectionError", "NoOptionError"]
+
+
+class INIConfigParser(SafeConfigParser):
+
+    """A case sensitive config parser that returns all-unicode string
+    values.
+
+    """
+
+    def __init__(self, filename, executable=None, encoding=None):
+        SafeConfigParser.__init__(self)
+        if executable is None:
+            executable = sys.argv[0]
+        if PY2:
+            if isinstance(filename, str):
+                filename = filename.decode(locale.getpreferredencoding())
+            if isinstance(executable, str):
+                executable = executable.decode(locale.getpreferredencoding())
+        self.executable = os.path.normpath(os.path.abspath(executable))
+        if encoding is None:
+            encoding = locale.getpreferredencoding()
+        self.encoding = encoding
+        with io.open(filename,
+                     mode="rt",
+                     encoding=self.encoding) as cf:
+            self.readfp(cf, filename)
+
+    def optionxform(self, option):
+        return option
+
+    def get_path_list(self, section, option):
+        v = self.get(section, option)
+        return v.split(os.pathsep)
+
+    def read(self, filenames):
+        raise NotImplementedError("use `readfp()' instead")
+
+    def readfp(self, fp, filename):
+        if hasattr(self, "filename"):
+            raise RuntimeError("already initialized")
+        filename = os.path.normpath(os.path.abspath(filename))
+        if PY2:
+            if isinstance(filename, str):
+                filename = filename.decode(locale.getpreferredencoding())
+        self.set(None, "self", filename)
+        self.set(None, "here", os.path.dirname(filename))
+        self.set(None, "root", os.path.dirname(self.executable))
+        SafeConfigParser.readfp(self, fp, filename=filename)
+        self.filename = filename
+        self.root = os.path.dirname(self.executable)
+
+    def getx(self, section, option):
+        """Extended get() with some automatic type conversion support.
+
+        Default: Fetch as string (like `get()`).
+
+        If annotated with ``:bool:`` fetch as bool, if annotated with
+        ``:int:`` fetch as int, if annotated with ``:float:`` fetch as
+        float.
+
+        """
+        v = self.get(section, option)
+        if v.startswith(":bool:"):
+            v = v[6:].lower()
+            if v not in self._BOOL_CVT:
+                raise ValueError("Not a boolean: %s" % (v, ))
+            return self._BOOL_CVT[v]
+        elif v.startswith(":int:"):
+            return int(v[5:], 0)
+        elif v.startswith(":float:"):
+            return float(v[7:])
+        else:
+            return v
+
+    _BOOL_CVT = {'1': True, 'yes': True, 'true': True, 'on': True,
+                 '0': False, 'no': False, 'false': False, 'off': False}