Mercurial > hgrepos > Python > libs > ConfigMix
diff configmix/__init__.py @ 144:7e6ec99d5ff5
Allow comments as keys and filter them by default
| author | Franz Glasner <hg@dom66.de> |
|---|---|
| date | Fri, 13 Apr 2018 09:51:02 +0200 |
| parents | 647782859ae1 |
| children | e2e8d21b4122 |
line wrap: on
line diff
--- a/configmix/__init__.py Mon Apr 09 09:35:04 2018 +0200 +++ b/configmix/__init__.py Fri Apr 13 09:51:02 2018 +0200 @@ -20,6 +20,7 @@ import copy +from .compat import u from .config import Configuration @@ -28,6 +29,15 @@ "Configuration"] +COMMENTS = [u("__comment"), + u("__doc"), +] +"""Prefixes for comment configuration keys that are to be handled as +comments + +""" + + def load(*files): """Load the given configuration files, merge them in the given order and return the resulting configuration dictionary. @@ -168,7 +178,7 @@ return result -def merge(user, default): +def merge(user, default, filter_comments=True): """Logically merge the configuration in `user` into `default`. :param ~configmix.config.Configuration user: @@ -176,73 +186,120 @@ into `default` :param ~configmix.config.Configuration default: the base configuration where `user` is logically merged into + :param bool filter_comments: flag whether to filter comment keys that + start with any of the items in :data:`COMMENTS` :returns: `user` with the necessary amendments from `default`. If `user` is ``None`` then `default` is returned. - .. note:: The configuration in `default` is not changed but the - configuration given in `user` is changed **inplace**. + .. note:: The configuration in `user` is augmented/changed + **inplace**. + + The configuration in `default` will be changed **inplace** + when filtering out comments (which is the default). From http://stackoverflow.com/questions/823196/yaml-merge-in-python """ if user is None: + if filter_comments: + _filter_comments(default) return default + if filter_comments: + _filter_comments(user) if isinstance(user, dict) and isinstance(default, dict): for k, v in default.items(): + if filter_comments and _is_comment(k): + continue if k not in user: user[k] = v else: - user[k] = _merge(user[k], v) + user[k] = _merge(user[k], v, filter_comments) return user -def _merge(user, default): +def _merge(user, default, filter_comments): """Recursion helper for :meth:`merge` """ if isinstance(user, dict) and isinstance(default, dict): for k, v in default.items(): + if filter_comments and _is_comment(k): + continue if k not in user: user[k] = v else: - user[k] = _merge(user[k], v) + user[k] = _merge(user[k], v, filter_comments) return user -def safe_merge(user, default): +def safe_merge(user, default, filter_comments=True): """A more safe version of :func:`merge` that makes deep copies of the returned container objects. - No given argument is ever changed inplace. Every object from `default` - is decoupled from the result -- so changing the `default` configuration - lates does not yield into a merged configuration later. + Contrary to :func:`merge` no given argument is ever changed + inplace. Every object from `default` is decoupled from the result + -- so changing the `default` configuration later does not yield + into a merged configuration later. """ if user is None: + if filter_comments: + _filter_comments(default) return copy.deepcopy(default) user = copy.deepcopy(user) + if filter_comments: + _filter_comments(user) if isinstance(user, dict) and isinstance(default, dict): for k, v in default.items(): + if filter_comments and _is_comment(k): + continue if k not in user: user[k] = copy.deepcopy(v) else: - user[k] = _safe_merge(user[k], v) + user[k] = _safe_merge(user[k], v, filter_comments) return user -def _safe_merge(user, default): +def _safe_merge(user, default, filter_comments): """Recursion helper for :meth:`safe_merge` """ if isinstance(user, dict) and isinstance(default, dict): for k, v in default.items(): + if filter_comments and _is_comment(k): + continue if k not in user: user[k] = copy.deepcopy(v) else: - user[k] = _safe_merge(user[k], v) + user[k] = _safe_merge(user[k], v, filter_comments) return user +def _filter_comments(d): + """Recursively filter comments keys in the dict `d`. + + Comment keys are keys that start with any of the items in + :data:`COMMENTS`. + + """ + if not isinstance(d, dict): + return + # use a copy of the keys because we change `d` while iterating + for k in list(d.keys()): + if _is_comment(k): + del d[k] + else: + if isinstance(d[k], dict): + _filter_comments(d[k]) + + +def _is_comment(k): + for i in COMMENTS: + if k.startswith(i): + return True + return False + + # # Init loader defaults #
