Mercurial > hgrepos > Python > libs > ConfigMix
view configmix/config.py @ 284:4aaf74858d07
Some links to AWS docu into the aws moduleSome links to AWS docu into the aws moduleSome links to AWS docu into the aws moduleSome links to AWS docu into the aws moduleSome links to AWS docu into the aws moduleSome links to AWS docu into the aws moduleSome links to AWS docu into the aws moduleSome links to AWS docu into the aws module
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 07 Dec 2020 01:59:11 +0100 |
| parents | 2a8dcab2de8c |
| children | eed16a1ec8f3 |
line wrap: on
line source
# -*- coding: utf-8 -*- # :- # :Copyright: (c) 2015-2020, Franz Glasner. All rights reserved. # :License: 3-clause BSD. See LICENSE.txt for details. # :- """The unified configuration dictionary with attribute support or variable substitution. """ from __future__ import division, absolute_import, print_function __all__ = ["Configuration"] import warnings try: from collections import OrderedDict as ConfigurationBase except ImportError: try: from ordereddict import OrderedDict as ConfigurationBase except ImportError: ConfigurationBase = dict from .variables import lookup_varns, lookup_filter from .compat import u _MARKER = object() class _AttributeDict(ConfigurationBase): def __getattr__(self, name): try: v = self[name] except KeyError: raise AttributeError("%s has no attribute %r" % (type(self), name)) else: # Wrap a dict into another dict with attribute access support if isinstance(v, dict): return _AttributeDict(v) else: return v class Configuration(_AttributeDict): """The configuration dictionary with attribute support or variable substitution. .. note:: When retriving by attribute names variables will *not* substituted. """ def getvar(self, varname, default=_MARKER): """Get a variable of the form ``[ns:][[key1.]key2.]name`` - including variables from other namespaces. No variable interpolation is done and no filters are applied. """ varns, varname = self._split_ns(varname) try: if not varns: lookupfn = self._lookupvar else: lookupfn = lookup_varns(varns) varvalue = lookupfn(varname) except KeyError: if default is _MARKER: raise KeyError("Variable %r not found" % varname) else: return default else: return varvalue def getvar_s(self, varname, default=_MARKER): """Get a variable - including variables from other namespaces. `varname` is interpreted as in :meth:`.getvar`. But variables will be interpolated recursively within the variable values and filters are applied. For more details see chapter :ref:`variable-interpolation`. """ try: obj = self.getvar(varname) return self.substitute_variables_in_obj(obj) except KeyError: if default is _MARKER: raise else: return default def getintvar_s(self, varname, default=_MARKER): """Get a (possibly substituted) variable and coerce text to a number. """ s = self.getvar_s(varname, default) if isinstance(s, self._TEXTTYPE): return int(s, 0) 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) 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 = {'1': True, 'yes': True, 'true': True, 'on': True, '0': False, 'no': False, 'false': False, 'off': False} 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 _split_ns(self, s): nameparts = s.split(':', 1) if len(nameparts) == 1: return (None, s, ) else: return (nameparts[0], nameparts[1], ) def _split_filters(self, s): nameparts = s.split('|') if len(nameparts) == 1: return (s, [], ) else: return (nameparts[0].rstrip(), nameparts[1:], ) def _lookupvar(self, key, default=_MARKER): """Lookup a variable. If no default is given an unexisting `key` raises a `KeyError` else `default` is returned. """ parts = key.split('.') try: v = self[parts[0]] for p in parts[1:]: v = v[p] except TypeError: raise KeyError( "Configuration variable %r not found" "(missing intermediate keys?)" % key) except KeyError: if default is _MARKER: raise KeyError("Configuration variable %r not found" % key) else: return default return v # Speed _TEXTTYPE = type(u("")) def substitute_variables_in_obj(self, obj): """Recursively expand variables in the object tree `obj`.""" if isinstance(obj, self._TEXTTYPE): # a string - really replace the value return self.expand_variable(obj) elif isinstance(obj, list): return [self.substitute_variables_in_obj(i) for i in obj] elif isinstance(obj, tuple): tmp = [self.substitute_variables_in_obj(i) for i in obj] return type(obj)(tmp) elif isinstance(obj, dict): newdict = type(obj)() for k in obj: newdict[k] = self.substitute_variables_in_obj(obj[k]) return newdict elif isinstance(obj, set): newset = type(obj)() for i in obj: newset.add(self.substitute_variables_in_obj(i)) else: return obj # Speed _STARTTOK = u(b"{{") _ENDTOK = u(b"}}") def expand_variable(self, s): """Expand variables in a single string""" start = s.find(self._STARTTOK, 0) while start != -1: end = s.find(self._ENDTOK, start) if end < 0: return s varname, filters = self._split_filters(s[start+2:end]) try: varvalue = self._apply_filters(filters, self.getvar_s(varname)) except KeyError: warnings.warn("Cannot expand variable %r in string " "%r" % (varname, s, ), UserWarning, stacklevel=1) raise if varvalue is None: varvalue = u("") # # Dont apply and type conversions to str if the whole `s` is # just one expansion # if (start == 0) and (end + 2 == len(s)): return varvalue replaced = s[:start] + u(str(varvalue)) s = replaced + s[end+2:] # don't re-evaluate because `self.getvar_s()` expands already start = s.find(self._STARTTOK, len(replaced)) return s def _apply_filters(self, filters, value): for name in filters: try: filterfn = lookup_filter(name) except KeyError: # # Convert to NameError because we find a missing filters # a very serious error. # raise NameError("Filter %r not found" % name) else: value = filterfn(self, value) return value
