changeset 412:816327e178b0

Provide coercing methods for the jailed configuration: getintXXX(), getboolXXX(), getfloatXXX() and friends. This is done be refactoring Configuration and putting the coercing methods into a common mixin.
author Franz Glasner <fzglas.hg@dom66.de>
date Sat, 20 Nov 2021 13:52:08 +0100
parents 3c95faa91dad
children ed24edf9ecf7
files CHANGES.txt configmix/config.py tests/data/conf10.ini tests/data/conf10.json tests/data/conf10.py tests/data/conf10.toml tests/data/conf10.yml tests/test.py
diffstat 8 files changed, 187 insertions(+), 154 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES.txt	Fri Nov 19 15:52:01 2021 +0100
+++ b/CHANGES.txt	Sat Nov 20 13:52:08 2021 +0100
@@ -12,6 +12,14 @@
 Pre-1.0 Series
 --------------
 
+none
+~~~~
+
+- **[feature]**
+  Complete the set of configuration retrieval methods for the jailed
+  configuration.
+
+
 0.17b2 (2021-11-19)
 ~~~~~~~~~~~~~~~~~~~
 
--- a/configmix/config.py	Fri Nov 19 15:52:01 2021 +0100
+++ b/configmix/config.py	Sat Nov 20 13:52:08 2021 +0100
@@ -50,7 +50,169 @@
                 return v
 
 
-class Configuration(_AttributeDict):
+class CoercingMethodsMixin(object):
+
+    """Mixin to provide some common implementations for retrieval
+    methods that convert return values to a fixed type (int, bool,
+    float).
+
+    Both :class:`~.Configuration` and :class:`~._JailedConfiguration` use
+    this mixin.
+
+    """
+
+    def getintvarl_s(self, *path, **kwds):
+        """Get a (possibly substituted) variable and coerce text to a
+        number.
+
+        """
+        s = self.getvarl_s(*path, **kwds)
+        if isinstance(s, Configuration._TEXTTYPE):
+            return int(s, 0)
+        else:
+            return s
+
+    def getfirstintvarl_s(self, *paths, **kwds):
+        """Get a (possibly substituted) variable and coerce text to a
+        number.
+
+        """
+        s = self.getfirstvarl_s(*paths, **kwds)
+        if isinstance(s, Configuration._TEXTTYPE):
+            return int(s, 0)
+        else:
+            return s
+
+    def getintvar_s(self, varname, default=_MARKER):
+        """Get a (possibly substituted) variable and coerce text to a
+        number.
+
+        """
+        s = self.getvar_s(varname, default=default)
+        if isinstance(s, Configuration._TEXTTYPE):
+            return int(s, 0)
+        else:
+            return s
+
+    def getfirstintvar_s(self, *varnames, **kwds):
+        """A variant of :meth:`~.getintvar_s` that returns the first found
+        variable in the list of given variables in `varnames`.
+
+        """
+        s = self.getfirstvar_s(*varnames, **kwds)
+        if isinstance(s, Configuration._TEXTTYPE):
+            return int(s, 0)
+        else:
+            return s
+
+    def getboolvarl_s(self, *path, **kwds):
+        """Get a (possibly substituted) variable and convert text to a
+        boolean
+
+        """
+        s = self.getvarl_s(*path, **kwds)
+        if isinstance(s, Configuration._TEXTTYPE):
+            sl = s.strip().lower()
+            if sl not in self._BOOL_CVT:
+                raise ValueError("Not a boolean: %r" % s)
+            return self._BOOL_CVT[sl]
+        else:
+            return s
+
+    def getfirstboolvarl_s(self, *paths, **kwds):
+        """Get a (possibly substituted) variable and convert text to a
+        boolean
+
+        """
+        s = self.getfirstvarl_s(*paths, **kwds)
+        if isinstance(s, Configuration._TEXTTYPE):
+            sl = s.strip().lower()
+            if sl not in self._BOOL_CVT:
+                raise ValueError("Not a boolean: %r" % s)
+            return self._BOOL_CVT[sl]
+        else:
+            return s
+
+    def getboolvar_s(self, varname, default=_MARKER):
+        """Get a (possibly substituted) variable and convert text to a
+        boolean
+
+        """
+        s = self.getvar_s(varname, default=default)
+        if isinstance(s, Configuration._TEXTTYPE):
+            sl = s.strip().lower()
+            if sl not in self._BOOL_CVT:
+                raise ValueError("Not a boolean: %r" % s)
+            return self._BOOL_CVT[sl]
+        else:
+            return s
+
+    def getfirstboolvar_s(self, *varnames, **kwds):
+        """A variant of :meth:`~.getboolvar_s` that returns the first found
+        variable in the list of given variables in `varnames`.
+
+        """
+        s = self.getfirstvar_s(*varnames, **kwds)
+        if isinstance(s, Configuration._TEXTTYPE):
+            sl = s.strip().lower()
+            if sl not in self._BOOL_CVT:
+                raise ValueError("Not a boolean: %r" % s)
+            return self._BOOL_CVT[sl]
+        else:
+            return s
+
+    # Conversion of booleans
+    _BOOL_CVT = {
+        u('1'): True, u('yes'): True, u('true'): True, u('on'): True,
+        u('0'): False, u('no'): False, u('false'): False, u('off'): False
+    }
+
+    def getfloatvarl_s(self, *path, **kwds):
+        """Get a (possibly substituted) variable and convert text to a
+        float
+
+        """
+        s = self.getvarl_s(*path, **kwds)
+        if isinstance(s, Configuration._TEXTTYPE):
+            return float(s)
+        else:
+            return s
+
+    def getfirstfloatvarl_s(self, *path, **kwds):
+        """Get a (possibly substituted) variable and convert text to a
+        float
+
+        """
+        s = self.getfirstvarl_s(*path, **kwds)
+        if isinstance(s, Configuration._TEXTTYPE):
+            return float(s)
+        else:
+            return s
+
+    def getfloatvar_s(self, varname, default=_MARKER):
+        """Get a (possibly substituted) variable and convert text to a
+        float
+
+        """
+        s = self.getvar_s(varname, default)
+        if isinstance(s, Configuration._TEXTTYPE):
+            return float(s)
+        else:
+            return s
+
+    def getfirstfloatvar_s(self, varname, default=_MARKER):
+        """Get a (possibly substituted) variable and convert text to a
+        float
+
+        """
+        s = self.getfirstvar_s(varname, default)
+        if isinstance(s, Configuration._TEXTTYPE):
+            return float(s)
+        else:
+            return s
+
+
+class Configuration(CoercingMethodsMixin, _AttributeDict):
 
     """The configuration dictionary with attribute support or
     variable substitution.
@@ -297,156 +459,6 @@
         else:
             return default
 
-    def getintvarl_s(self, *path, **kwds):
-        """Get a (possibly substituted) variable and coerce text to a
-        number.
-
-        """
-        s = self.getvarl_s(*path, **kwds)
-        if isinstance(s, self._TEXTTYPE):
-            return int(s, 0)
-        else:
-            return s
-
-    def getfirstintvarl_s(self, *paths, **kwds):
-        """Get a (possibly substituted) variable and coerce text to a
-        number.
-
-        """
-        s = self.getfirstvarl_s(*paths, **kwds)
-        if isinstance(s, self._TEXTTYPE):
-            return int(s, 0)
-        else:
-            return s
-
-    def getintvar_s(self, varname, default=_MARKER):
-        """Get a (possibly substituted) variable and coerce text to a
-        number.
-
-        """
-        s = self.getvar_s(varname, default=default)
-        if isinstance(s, self._TEXTTYPE):
-            return int(s, 0)
-        else:
-            return s
-
-    def getfirstintvar_s(self, *varnames, **kwds):
-        """A variant of :meth:`~.getintvar_s` that returns the first found
-        variable in the list of given variables in `varnames`.
-
-        """
-        s = self.getfirstvar_s(*varnames, **kwds)
-        if isinstance(s, self._TEXTTYPE):
-            return int(s, 0)
-        else:
-            return s
-
-    def getboolvarl_s(self, *path, **kwds):
-        """Get a (possibly substituted) variable and convert text to a
-        boolean
-
-        """
-        s = self.getvarl_s(*path, **kwds)
-        if isinstance(s, self._TEXTTYPE):
-            sl = s.strip().lower()
-            if sl not in self._BOOL_CVT:
-                raise ValueError("Not a boolean: %r" % s)
-            return self._BOOL_CVT[sl]
-        else:
-            return s
-
-    def getfirstboolvarl_s(self, *paths, **kwds):
-        """Get a (possibly substituted) variable and convert text to a
-        boolean
-
-        """
-        s = self.getfirstvarl_s(*paths, **kwds)
-        if isinstance(s, self._TEXTTYPE):
-            sl = s.strip().lower()
-            if sl not in self._BOOL_CVT:
-                raise ValueError("Not a boolean: %r" % s)
-            return self._BOOL_CVT[sl]
-        else:
-            return s
-
-    def getboolvar_s(self, varname, default=_MARKER):
-        """Get a (possibly substituted) variable and convert text to a
-        boolean
-
-        """
-        s = self.getvar_s(varname, default=default)
-        if isinstance(s, self._TEXTTYPE):
-            sl = s.strip().lower()
-            if sl not in self._BOOL_CVT:
-                raise ValueError("Not a boolean: %r" % s)
-            return self._BOOL_CVT[sl]
-        else:
-            return s
-
-    def getfirstboolvar_s(self, *varnames, **kwds):
-        """A variant of :meth:`~.getboolvar_s` that returns the first found
-        variable in the list of given variables in `varnames`.
-
-        """
-        s = self.getfirstvar_s(*varnames, **kwds)
-        if isinstance(s, self._TEXTTYPE):
-            sl = s.strip().lower()
-            if sl not in self._BOOL_CVT:
-                raise ValueError("Not a boolean: %r" % s)
-            return self._BOOL_CVT[sl]
-        else:
-            return s
-
-    # Conversion of booleans
-    _BOOL_CVT = {
-        u('1'): True, u('yes'): True, u('true'): True, u('on'): True,
-        u('0'): False, u('no'): False, u('false'): False, u('off'): False
-    }
-
-    def getfloatvarl_s(self, *path, **kwds):
-        """Get a (possibly substituted) variable and convert text to a
-        float
-
-        """
-        s = self.getvarl_s(*path, **kwds)
-        if isinstance(s, self._TEXTTYPE):
-            return float(s)
-        else:
-            return s
-
-    def getfirstfloatvarl_s(self, *path, **kwds):
-        """Get a (possibly substituted) variable and convert text to a
-        float
-
-        """
-        s = self.getfirstvarl_s(*path, **kwds)
-        if isinstance(s, self._TEXTTYPE):
-            return float(s)
-        else:
-            return s
-
-    def getfloatvar_s(self, varname, default=_MARKER):
-        """Get a (possibly substituted) variable and convert text to a
-        float
-
-        """
-        s = self.getvar_s(varname, default)
-        if isinstance(s, self._TEXTTYPE):
-            return float(s)
-        else:
-            return s
-
-    def getfirstfloatvar_s(self, varname, default=_MARKER):
-        """Get a (possibly substituted) variable and convert text to a
-        float
-
-        """
-        s = self.getfirstvar_s(varname, default)
-        if isinstance(s, self._TEXTTYPE):
-            return float(s)
-        else:
-            return s
-
     def _split_ns(self, s):
         nameparts = s.split(self._NS_SEPARATOR, 1)
         if len(nameparts) == 1:
@@ -693,7 +705,7 @@
         return jc
 
 
-class _JailedConfiguration(object):
+class _JailedConfiguration(CoercingMethodsMixin):
 
     """A jailed and restricted variant of :class:`Configuration`.
 
--- a/tests/data/conf10.ini	Fri Nov 19 15:52:01 2021 +0100
+++ b/tests/data/conf10.ini	Sat Nov 20 13:52:08 2021 +0100
@@ -13,3 +13,4 @@
 [config.tree1.tree2]
 key4 = get this as `tree1.tree2.key4'
 key5 = :bool:TRUE
+key6 = off
--- a/tests/data/conf10.json	Fri Nov 19 15:52:01 2021 +0100
+++ b/tests/data/conf10.json	Sat Nov 20 13:52:08 2021 +0100
@@ -4,7 +4,8 @@
      "key3": 32,
      "tree2": {
 	 "key4": "get this as `tree1.tree2.key4'",
-	 "key5": true
+	 "key5": true,
+	 "key6": "off"
      }
  }
 }
--- a/tests/data/conf10.py	Fri Nov 19 15:52:01 2021 +0100
+++ b/tests/data/conf10.py	Sat Nov 20 13:52:08 2021 +0100
@@ -8,7 +8,8 @@
 
     'tree2': {
         'key4': u"get this as `tree1.tree2.key4'",
-        'key5': True
+        'key5': True,
+        'key6': u"off"
     }
 }
 
--- a/tests/data/conf10.toml	Fri Nov 19 15:52:01 2021 +0100
+++ b/tests/data/conf10.toml	Sat Nov 20 13:52:08 2021 +0100
@@ -9,3 +9,4 @@
 [tree1.tree2]
 key4 = "get this as `tree1.tree2.key4'"
 key5 = true
+key6 = "off"
--- a/tests/data/conf10.yml	Fri Nov 19 15:52:01 2021 +0100
+++ b/tests/data/conf10.yml	Sat Nov 20 13:52:08 2021 +0100
@@ -10,3 +10,4 @@
   tree2:
     key4: get this as `tree1.tree2.key4'
     key5: true
+    key6: 'off'
--- a/tests/test.py	Fri Nov 19 15:52:01 2021 +0100
+++ b/tests/test.py	Sat Nov 20 13:52:08 2021 +0100
@@ -1431,6 +1431,14 @@
         # base is not because rebind() failed
         self.assertTrue(cfg is jcfg1.base)
 
+    def test_getbool(self):
+        cfg = configmix.load(os.path.join(TESTDATADIR, "conf10.py"))
+        jcfg = cfg.jailed(rootpath=(u"tree1", u"tree2"))
+
+        self.assertFalse(jcfg.getboolvar_s(u"key6"))
+        self.assertEqual(u"off", jcfg.getvarl_s(u"key6"))
+        self.assertTrue(jcfg.getvar_s(u"key6"))
+
 
 if __name__ == "__main__":
     unittest.main()