changeset 381:fe3dfd687621

Implemented Configuration.getfirstvarl() and Configuration.getfirstvarl_s()
author Franz Glasner <fzglas.hg@dom66.de>
date Wed, 10 Nov 2021 01:37:36 +0100
parents bb4a90fb58e0
children 24db29162d09
files CHANGES.txt configmix/config.py tests/test.py
diffstat 3 files changed, 197 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES.txt	Tue Nov 09 21:58:05 2021 +0100
+++ b/CHANGES.txt	Wed Nov 10 01:37:36 2021 +0100
@@ -12,6 +12,14 @@
 Pre-1.0 Series
 --------------
 
+none (none)
+~~~~~~~~~~~
+
+- **[feature]** New access methods
+  :py:meth:`~configmix.config.Configuration.getfirstvarl`,
+  :py:meth:`~configmix.config.Configuration.getfirstvarl_s`
+
+
 0.16 (2021-07-11)
 ~~~~~~~~~~~~~~~~~
 
--- a/configmix/config.py	Tue Nov 09 21:58:05 2021 +0100
+++ b/configmix/config.py	Wed Nov 10 01:37:36 2021 +0100
@@ -101,6 +101,38 @@
         else:
             return varvalue
 
+    def getfirstvarl(self, *paths, **kwds):
+        default = kwds.pop("default", _MARKER)
+        for path in paths:
+            if isinstance(path, (list, tuple)):
+                try:
+                    varvalue = self.getvarl(*path)
+                except KeyError:
+                    pass
+                else:
+                    return varvalue
+            elif isinstance(path, dict):
+                try:
+                    namespace = path["namespace"]
+                    p = path["path"]
+                except KeyError:
+                    raise TypeError("a paths dict item must have a `path'"
+                                    " and a `namespace' key")
+                else:
+                    try:
+                        varvalue = self.getvarl(*p, namespace=namespace)
+                    except KeyError:
+                        pass
+                    else:
+                        return varvalue
+            else:
+                raise TypeError("a paths item must be a dict, list or tuple")
+        if default is _MARKER:
+            raise KeyError(
+                "none of the given variables found: %r" % (paths,))
+        else:
+            return default
+
     def getvar(self, varname, default=_MARKER):
         """Get a variable of the form ``[ns:][[key1.]key2.]name`` - including
         variables from other namespaces.
@@ -161,6 +193,39 @@
             else:
                 return default
 
+    def getfirstvarl_s(self, *paths, **kwds):
+        default = kwds.pop("default", _MARKER)
+        for path in paths:
+            if isinstance(path, (list, tuple)):
+                try:
+                    obj = self.getvarl(*path)
+                except KeyError:
+                    pass
+                else:
+                    return self.substitute_variables_in_obj(obj)
+
+            elif isinstance(path, dict):
+                try:
+                    namespace = path["namespace"]
+                    p = path["path"]
+                except KeyError:
+                    raise TypeError("a paths dict item must have a `path'"
+                                    " and a `namespace' key")
+                else:
+                    try:
+                        obj = self.getvarl(*p, namespace=namespace)
+                    except KeyError:
+                        pass
+                    else:
+                        return self.substitute_variables_in_obj(obj)
+            else:
+                raise TypeError("a paths item must be a dict, list or tuple")
+        if default is _MARKER:
+            raise KeyError(
+                "none of the given variables found: %r" % (paths,))
+        else:
+            return default
+
     def getvar_s(self, varname, default=_MARKER):
         """Get a variable - including variables from other namespaces.
 
--- a/tests/test.py	Tue Nov 09 21:58:05 2021 +0100
+++ b/tests/test.py	Wed Nov 10 01:37:36 2021 +0100
@@ -581,6 +581,130 @@
                                   "db.non.existing.key2",
                                   default=u("true")))
 
+    def test27_getfirstvarl_nonexisting(self):
+        cfg = self._load(os.path.join(TESTDATADIR, "conf20.yml"))
+        self.assertRaises(
+            KeyError,
+            cfg.getfirstvarl,
+            [["db", "non", "existing", "key"],
+             ("db", "non", "existing", "key2")])
+
+    def test27b_getfirstvarl_nonexisting(self):
+        cfg = self._load(os.path.join(TESTDATADIR, "conf20.yml"))
+        self.assertRaises(
+            KeyError,
+            cfg.getfirstvarl,
+            [{"namespace": None, "path": ["db", "non", "existing", "key"]},
+             {"namespace": None, "path": ["db", "non", "existing", "key2"]}])
+
+    def test28_getfirstvarl_nonexisting(self):
+        cfg = self._load(os.path.join(TESTDATADIR, "conf20.yml"))
+        self.assertIsNone(cfg.getfirstvarl(
+            [["db", "non", "existing", "key"],
+             ("db", "non", "existing", "key2")],
+            default=None))
+
+    def test28b_getfirstvarl_nonexisting(self):
+        cfg = self._load(os.path.join(TESTDATADIR, "conf20.yml"))
+        self.assertIsNone(cfg.getfirstvarl(
+            [{"namespace": None, "path": ["db", "non", "existing", "key"]},
+             {"namespace": None, "path": ("db", "non", "existing", "key2")}],
+            default=None))
+
+    def test29_getfirstvarl_existing(self):
+        cfg = self._load(os.path.join(TESTDATADIR, "conf20.yml"))
+        self.assertEqual(
+            "test-configmix",
+            cfg.getfirstvarl(*(("intl", "domain"),)))
+        self.assertEqual(
+            "test-configmix",
+            cfg.getfirstvarl(*(("intl", "domain"), ("intl", "fallback"))))
+        self.assertEqual(
+            "de",
+            cfg.getfirstvarl(*[["intl", "fallback"],
+                               ["intl", "domain"]],
+                               default=None))
+        self.assertEqual(
+            "de",
+            cfg.getfirstvarl(*[["intl", "non", "existing"],
+                               ["intl", "fallback"]],
+                               default=None))
+
+    def test29b_getfirstvarl_existing(self):
+        cfg = self._load(os.path.join(TESTDATADIR, "conf20.yml"))
+        self.assertEqual(
+            "test-configmix",
+            cfg.getfirstvarl(*({"namespace": None,
+                                "path": ("intl", "domain")},)))
+        self.assertEqual(
+            "test-configmix",
+            cfg.getfirstvarl(*({"namespace": None,
+                                "path": ("intl", "domain")},
+                               {"namespace": None, "path": ("intl", "fallback")})))
+        self.assertEqual(
+            "de",
+            cfg.getfirstvarl(*[{"namespace": None, "path": ["intl", "fallback"]},
+                               {"namespace": None, "path": ["intl", "domain"]}],
+                               default=None))
+        self.assertEqual(
+            "de",
+            cfg.getfirstvarl(*[{"namespace": None, "path": ["intl", "non", "existing"]},
+                               {"namespace": None, "path": ["intl", "fallback"]}],
+                               default=None))
+
+    def test30_getfirstvarl_s_existing(self):
+        cfg = self._load(
+            os.path.join(TESTDATADIR, "conf20.yml"),
+            os.path.join(TESTDATADIR, "conf21.yml"))
+        self.assertEqual(
+            os.getcwd()+"/locale",
+            cfg.getfirstvarl_s(*[["intl", "non", "existing"],
+                                 ["intl", "localedir"]]))
+        self.assertEqual(
+            os.getcwd()+"/locale",
+            cfg.getfirstvarl_s(*[["intl", "localedir"], ["intl", "non", "existing"]]))
+
+    def test30b_getfirstvarl_s_existing(self):
+        cfg = self._load(
+            os.path.join(TESTDATADIR, "conf20.yml"),
+            os.path.join(TESTDATADIR, "conf21.yml"))
+        self.assertEqual(
+            os.getcwd()+"/locale",
+            cfg.getfirstvarl_s(*[{"namespace": None, "path": ["intl", "non", "existing"]},
+                                 {"namespace": None, "path": ["intl", "localedir"]}]))
+        self.assertEqual(
+            os.getcwd()+"/locale",
+            cfg.getfirstvarl_s(*[{"namespace": None, "path": ["intl", "localedir"]}, {"namespace": None, "path": ["intl", "non", "existing"]}]))
+
+    def test31_getfirstvar_s_non_existing(self):
+        cfg = self._load(
+            os.path.join(TESTDATADIR, "conf20.yml"),
+            os.path.join(TESTDATADIR, "conf21.yml"))
+        self.assertIsNone(
+            cfg.getfirstvarl_s(
+                *[["intl", "non", "existing"], ["intl", "non", "existing2"]],
+                default=None))
+        self.assertRaises(
+            KeyError,
+            cfg.getfirstvarl_s,
+            ["intl" ,"non", "existing"],
+            ["intl", "non", "existing2"])
+
+    def test31b_getfirstvar_s_non_existing(self):
+        cfg = self._load(
+            os.path.join(TESTDATADIR, "conf20.yml"),
+            os.path.join(TESTDATADIR, "conf21.yml"))
+        self.assertIsNone(
+            cfg.getfirstvarl_s(
+                *[{"namespace": None, "path": ["intl", "non", "existing"]},
+                  {"namespace": None, "path": ["intl", "non", "existing2"]}],
+                default=None))
+        self.assertRaises(
+            KeyError,
+            cfg.getfirstvarl_s,
+            {"namespace": None, "path": ["intl" ,"non", "existing"]},
+            {"namespace": None, "path": ["intl", "non", "existing2"]})
+
 
 class T02LoadAndMerge(_T02MixinLoadAndMerge, unittest.TestCase):