Mercurial > hgrepos > Python > libs > ConfigMix
diff configmix/config.py @ 305:f529ca46dd50
Implemented the "ref" namespace to get configuration tree references.
BUGS:
- Tests should be done more thoroughly and extensively
- Interaction of tree references and variable substitution should be
tested more properly
- Documentation is missing yet
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 26 Apr 2021 09:42:42 +0200 |
| parents | d8361dd70d2d |
| children | 801cd16223e4 |
line wrap: on
line diff
--- a/configmix/config.py Sun Apr 25 18:05:26 2021 +0200 +++ b/configmix/config.py Mon Apr 26 09:42:42 2021 +0200 @@ -22,9 +22,14 @@ from ordereddict import OrderedDict as ConfigurationBase except ImportError: ConfigurationBase = dict +try: + from urllib.parse import urlsplit +except ImportError: + from urlparse import urlsplit from .variables import lookup_varns, lookup_filter from .compat import u +from .constants import REF_NAMESPACE _MARKER = object() @@ -55,6 +60,16 @@ """ + # Speed + _TEXTTYPE = type(u("")) + _STARTTOK = u(b"{{") + _ENDTOK = u(b"}}") + _NS_SEPARATOR = u(b':') + _FILTER_SEPARATOR = u(b'|') + _STARTTOK_REF = _STARTTOK + REF_NAMESPACE + _NS_SEPARATOR + _ENDTOK_REF = _ENDTOK + _DOT = u(b'.') + def getvar(self, varname, default=_MARKER): """Get a variable of the form ``[ns:][[key1.]key2.]name`` - including variables from other namespaces. @@ -67,7 +82,10 @@ if not varns: lookupfn = self._lookupvar else: - lookupfn = lookup_varns(varns) + if varns == REF_NAMESPACE: + lookupfn = self._lookupref + else: + lookupfn = lookup_varns(varns) varvalue = lookupfn(varname) except KeyError: if default is _MARKER: @@ -139,14 +157,14 @@ return s def _split_ns(self, s): - nameparts = s.split(':', 1) + nameparts = s.split(self._NS_SEPARATOR, 1) if len(nameparts) == 1: return (None, s, ) else: return (nameparts[0], nameparts[1], ) def _split_filters(self, s): - nameparts = s.split('|') + nameparts = s.split(self._FILTER_SEPARATOR) if len(nameparts) == 1: return (s, [], ) else: @@ -160,9 +178,9 @@ """ parts = key.split('.') try: - v = self[parts[0]] + v = self.expand_if_reference(self[parts[0]]) for p in parts[1:]: - v = v[p] + v = self.expand_if_reference(v[p]) except TypeError: raise KeyError( "Configuration variable %r not found" @@ -174,8 +192,41 @@ return default return v - # Speed - _TEXTTYPE = type(u("")) + def _lookupref(self, key, default=_MARKER): + """ + `key` must be a reference URI without any (namespace) prefixes + and suffixes + + """ + return self.expand_ref_uri(key, default=default) + + def expand_if_reference(self, v, default=_MARKER): + """Check whether `v` is a reference and -- if true -- then expand it. + + `v` must match the pattern ``{{{ref:<REFERENCE>}}}`` + + All non-matching texttypes and all non-texttypes are returned + unchanged. + + """ + if not isinstance(v, self._TEXTTYPE): + return v + if not v.startswith(self._STARTTOK_REF) \ + or not v.endswith(self._ENDTOK_REF): + return v + return self.expand_ref_uri( + v[len(self._STARTTOK_REF):-len(self._ENDTOK_REF)], + default=default) + + def expand_ref_uri(self, uri, default=_MARKER): + pu = urlsplit(uri) + if pu.scheme or pu.netloc or pu.path or pu.query: + raise ValueError("only fragment-only URIs are supported") + if not pu.fragment: + return self + if pu.fragment.startswith(self._DOT): + raise ValueError("relative refs not supported") + return self.getvar(pu.fragment, default=default) def substitute_variables_in_obj(self, obj): """Recursively expand variables in the object tree `obj`.""" @@ -199,10 +250,6 @@ else: return obj - # Speed - _STARTTOK = u(b"{{") - _ENDTOK = u(b"}}") - def expand_variable(self, s): """Expand variables in the single string `s`""" start = s.find(self._STARTTOK, 0)
