# HG changeset patch # User Franz Glasner # Date 1636504656 -3600 # Node ID fe3dfd687621d7751df735ad4a5c2d3a850b5c96 # Parent bb4a90fb58e0db90b6fb35fb9a0e1399fabbbff4 Implemented Configuration.getfirstvarl() and Configuration.getfirstvarl_s() diff -r bb4a90fb58e0 -r fe3dfd687621 CHANGES.txt --- 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) ~~~~~~~~~~~~~~~~~ diff -r bb4a90fb58e0 -r fe3dfd687621 configmix/config.py --- 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. diff -r bb4a90fb58e0 -r fe3dfd687621 tests/test.py --- 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):