Mercurial > hgrepos > Python > libs > ConfigMix
changeset 539:9546d38cd3f8
Refactor: the parsing of the quoted and dot-separated path string is put into a function that handles also empty inputs properly
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Tue, 28 Dec 2021 17:28:19 +0100 |
| parents | e85d1eddf539 |
| children | 33856ae1cc0b |
| files | configmix/__init__.py configmix/config.py tests/_perf_config.py |
| diffstat | 3 files changed, 65 insertions(+), 62 deletions(-) [+] |
line wrap: on
line diff
--- a/configmix/__init__.py Tue Dec 28 16:30:48 2021 +0100 +++ b/configmix/__init__.py Tue Dec 28 17:28:19 2021 +0100 @@ -32,7 +32,7 @@ import re from .compat import u2fs -from .config import Configuration, quote, unquote # noqa: F401 +from .config import Configuration, quote, unquote, pathstr2path # noqa: F401 from . import constants
--- a/configmix/config.py Tue Dec 28 16:30:48 2021 +0100 +++ b/configmix/config.py Tue Dec 28 17:28:19 2021 +0100 @@ -317,6 +317,34 @@ return _EMPTY_STR.join(res) +def pathstr2path(varname): + """Parse a dot-separated path string `varname` into a tuple of + unquoted path items + + :param str varname: The quoted and dot-separated path string + :return: The unquoted and parsed path items + :rtype: tuple + + Used e.g. by :meth:`~.Configuration.getvar`, + :meth:`~.Configuration.getvar_s` and :meth:`~.Configuration.jailed`. + + The returned value is suitable as input for + :meth:`~.Configuration.getvarl`, :meth:`~.Configuration.getvarl_s` and + friends. + + An empty `varname` returns an empty tuple. + + """ + # + # Because str.split yields a non-empty list for an empty string handle + # the empty string separately. + # + if varname: + return tuple([unquote(p) for p in varname.split(_HIER_SEPARATOR)]) + else: + return tuple() + + class Configuration(CoercingMethodsMixin, _AttributeDict): """The configuration dictionary with attribute support or @@ -497,14 +525,9 @@ """ varns, varname = self._split_ns(varname) if not varns: - if varname: - varnameparts = tuple([unquote(vp) - for vp in varname.split(_HIER_SEPARATOR)]) - else: - varnameparts = tuple() + return self.getvarl(*pathstr2path(varname), default=default) else: - varnameparts = (varname,) - return self.getvarl(*varnameparts, namespace=varns, default=default) + return self.getvarl(varname, namespace=varns, default=default) def getkeys(self, varname): """Yield all the keys of a variable value. @@ -614,17 +637,13 @@ """ varns, varname = self._split_ns(varname) - if not varns: - if varname: - varnameparts = tuple([unquote(vp) - for vp in varname.split(_HIER_SEPARATOR)]) + try: + if not varns: + return self.substitute_variables_in_obj( + self.getvarl(*pathstr2path(varname))) else: - varnameparts = tuple() - else: - varnameparts = (varname,) - try: - obj = self.getvarl(*varnameparts, namespace=varns) - return self.substitute_variables_in_obj(obj) + return self.substitute_variables_in_obj( + self.getvarl(varname, namespace=varns)) except KeyError: if default is _MARKER: raise @@ -642,17 +661,19 @@ """ varns, varname = self._split_ns(varname) if not varns: - cacheable = True - if varname: - varnameparts = tuple([unquote(vp) - for vp in varname.split(_HIER_SEPARATOR)]) - else: - varnameparts = tuple() + # no namespace -> cacheable + return ( + self.substitute_variables_in_obj( + self.getvarl(*pathstr2path(varname))), + True + ) else: - cacheable = False - varnameparts = (varname,) - obj = self.getvarl(*varnameparts, namespace=varns) - return (self.substitute_variables_in_obj(obj), cacheable) + # results from namespaced lookups are currently not cacheable + return ( + self.substitute_variables_in_obj( + self.getvarl(varname, namespace=varns)), + False + ) def getfirstvar_s(self, *varnames, **kwds): """A variant of :meth:`~.getvar_s` that returns the first found @@ -820,7 +841,7 @@ rest = start break varname, filters = self._split_filters( - s[start+2:end]) + s[start+2:end]) # noqa: E226 try: varvalue, cacheable = self._getvar_s_with_cache_info(varname) except KeyError: @@ -905,11 +926,7 @@ if varns: raise ValueError( "jailed configurations do not support namespaces") - if varname: - rootpath = tuple([unquote(p) - for p in root.split(_HIER_SEPARATOR)]) - else: - rootpath = tuple() + rootpath = pathstr2path(root) jc = _JailedConfiguration(*rootpath) if bind_root: jc.rebind(self) @@ -1071,22 +1088,11 @@ return self._base.getfirstvarl_s(*real_paths, **kwds) def getvar(self, varname, **kwds): - if varname: - varnameparts = self._path \ - + tuple([unquote(vp) - for vp in varname.split(_HIER_SEPARATOR)]) - else: - varnameparts = self._path - return self._base.getvarl(*varnameparts, **kwds) + return self._base.getvarl(*(self._path + pathstr2path(varname)), + **kwds) def getkeys(self, varname): - if varname: - varnameparts = self._path \ - + tuple([unquote(vp) - for vp in varname.split(_HIER_SEPARATOR)]) - else: - varnameparts = self._path - for k in self._base.getkeysl(*varnameparts): + for k in self._base.getkeysl(*(self._path + pathstr2path(varname))): yield k def getfirstvar(self, *varnames, **kwds): @@ -1094,13 +1100,8 @@ return self._base.getfirstvar(*real_varnames, **kwds) def getvar_s(self, varname, **kwds): - if varname: - varnameparts = self._path \ - + tuple([unquote(vp) - for vp in varname.split(_HIER_SEPARATOR)]) - else: - varnameparts = self._path - return self._base.getvarl_s(*varnameparts, **kwds) + return self._base.getvarl_s(*(self._path + pathstr2path(varname)), + **kwds) def getfirstvar_s(self, *varnames, **kwds): real_varnames = [self._pathstr + vn for vn in varnames] @@ -1145,11 +1146,7 @@ if varns: raise ValueError( "sub-jails do not support namespaces") - if varname: - rootpath = tuple([unquote(p) - for p in varname.split(_HIER_SEPARATOR)]) - else: - rootpath = tuple() + rootpath = pathstr2path(varname) if self._path: new_rootpath = self._path + tuple(rootpath) else:
--- a/tests/_perf_config.py Tue Dec 28 16:30:48 2021 +0100 +++ b/tests/_perf_config.py Tue Dec 28 17:28:19 2021 +0100 @@ -29,20 +29,26 @@ unquote = configmix.unquote quote = configmix.quote +pathstr2path = configmix.pathstr2path cfg = configmix.load(os.path.join(TESTDATADIR, "conf_perf.py")) +se = u"" +s1 = u"abc.def.hij" + """ num = 1000000 num_quote = 1 * num -if all or "quote" in opts or "unquote" in opts: - print("unquote/nothing/split: %.4f" % timeit.timeit('a = [unquote(vp) for vp in u"abc.def.hij".split(configmix.config._HIER_SEPARATOR)]', setup=setup, number=num_quote)) +if all or "quote" in opts or "unquote" in opts or "path" in opts: + print("unquote/nothing/split: %.4f" % timeit.timeit('a = tuple([unquote(vp) for vp in u"abc.def.hij".split(configmix.config._HIER_SEPARATOR)])', setup=setup, number=num_quote)) print("unquote/yes/split: %.4f" % timeit.timeit('a = [unquote(vp) for vp in u"ab%x20.def.h%x2ej".split(configmix.config._HIER_SEPARATOR)]', setup=setup, number=num_quote)) print("unquote/nothing/no-split: %.4f" % timeit.timeit('a = [unquote(vp) for vp in (u"abc," u"def", u"hij")]', setup=setup, number=num_quote)) print("unquote/yes/no-split: %.4f" % timeit.timeit('a = [unquote(vp) for vp in (u"ab%x20", u"def", u"h%x2ej")]', setup=setup, number=num_quote)) + print("pathstr2path/non-empty: %.4f" % timeit.timeit('a = pathstr2path(s1)', setup=setup, number=num_quote)) + print("pathstr2path/empty: %.4f" % timeit.timeit('a = pathstr2path(se)', setup=setup, number=num_quote)) print("quote/nothing: %.4f" % timeit.timeit('a = [quote(vp) for vp in (u"abc", u"def", u"hij")]', setup=setup, number=num_quote)) print("quote/yes: %.4f" % timeit.timeit('a = [quote(vp) for vp in (u"ab:c", u"def", u"h.ij")]', setup=setup, number=num_quote)) print("="*50)
