From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) by finch.gentoo.org (Postfix) with ESMTP id 65423138B38 for ; Sun, 26 Jan 2014 19:07:03 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 0F301E0B18; Sun, 26 Jan 2014 19:07:00 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 4FCB7E0B18 for ; Sun, 26 Jan 2014 19:06:58 +0000 (UTC) Received: from spoonbill.gentoo.org (spoonbill.gentoo.org [81.93.255.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id B66BE33F616 for ; Sun, 26 Jan 2014 19:06:57 +0000 (UTC) Received: from localhost.localdomain (localhost [127.0.0.1]) by spoonbill.gentoo.org (Postfix) with ESMTP id E175318096 for ; Sun, 26 Jan 2014 19:06:55 +0000 (UTC) From: "André Erdmann" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "André Erdmann" Message-ID: <1390754264.d72284c4978f84bbdcdc54ce0c4b4d66b6d91ad3.dywi@gentoo> Subject: [gentoo-commits] proj/R_overlay:master commit in: roverlay/config/ X-VCS-Repository: proj/R_overlay X-VCS-Files: roverlay/config/entryutil.py roverlay/config/exceptions.py roverlay/config/tree.py X-VCS-Directories: roverlay/config/ X-VCS-Committer: dywi X-VCS-Committer-Name: André Erdmann X-VCS-Revision: d72284c4978f84bbdcdc54ce0c4b4d66b6d91ad3 X-VCS-Branch: master Date: Sun, 26 Jan 2014 19:06:55 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Archives-Salt: 72a897fd-6f8d-4122-9006-fc296ebfb851 X-Archives-Hash: abb9bc8ddc1dd5d4b388e91b36aea61b commit: d72284c4978f84bbdcdc54ce0c4b4d66b6d91ad3 Author: André Erdmann mailerd de> AuthorDate: Sun Jan 26 16:37:44 2014 +0000 Commit: André Erdmann mailerd de> CommitDate: Sun Jan 26 16:37:44 2014 +0000 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=d72284c4 roverlay/config/, ConfigTree: get options by name Added get_by_name() to the ConfigTree, which is similar to get(), but takes an option name (used in config files, e.g. OVERLAY_DIR) instead of a config path (used in the code, e.g. ['OVERLAY','dir']) as key. query_by_name() can be used to get multiple options and return them as dict. Might be useful for scripting. --- roverlay/config/entryutil.py | 43 +++++++++++++++----- roverlay/config/exceptions.py | 40 +++++++++++++++++++ roverlay/config/tree.py | 92 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 159 insertions(+), 16 deletions(-) diff --git a/roverlay/config/entryutil.py b/roverlay/config/entryutil.py index cd5f230..716c166 100644 --- a/roverlay/config/entryutil.py +++ b/roverlay/config/entryutil.py @@ -1,6 +1,6 @@ # R overlay -- config package, entryutil # -*- coding: utf-8 -*- -# Copyright (C) 2012 André Erdmann +# Copyright (C) 2012-2014 André Erdmann # Distributed under the terms of the GNU General Public License; # either version 2 of the License, or (at your option) any later version. @@ -11,9 +11,11 @@ __all__ = [ 'list_entries', ] import re import textwrap +import roverlay.config.exceptions from roverlay.config.entrymap import CONFIG_ENTRY_MAP def deref_entry ( name ): + # COULDFIX: raise ConfigOptionNotFound entry_name = name.lower() entry_next = CONFIG_ENTRY_MAP [entry_name] while isinstance ( entry_next, str ): @@ -25,29 +27,50 @@ def deref_entry ( name ): def deref_entry_safe ( name ): visited = set() entry_name = name.lower() - entry_next = CONFIG_ENTRY_MAP [entry_name] + try: + entry_next = CONFIG_ENTRY_MAP [entry_name] + except KeyError: + # entry does not exist + raise roverlay.config.exceptions.ConfigOptionNotFound ( name ) while isinstance ( entry_next, str ): visited.add ( entry_name ) entry_name = entry_next - entry_next = CONFIG_ENTRY_MAP [entry_name] + try: + entry_next = CONFIG_ENTRY_MAP [entry_name] + except KeyError: + raise roverlay.config.exceptions.ConfigEntryMapException ( + "dangling config map entry {!r} (<- {!r})".format ( + entry_name, name + ) + ) if entry_name in visited: - raise Exception ( - "cyclic config entry detected for {!r}!".format ( name ) - ) + raise roverlay.config.exceptions.ConfigEntryMapException ( + "cyclic config entry detected for {!r}!".format ( name ) + ) return ( entry_name, entry_next ) # --- end of deref_entry_safe (...) --- def find_config_path ( name ): entry_name, entry = deref_entry_safe ( name ) - try: - return entry ['path'] - except KeyError: - return entry_name.split ( '_' ) + if entry: + try: + return entry ['path'] + except KeyError: + return entry_name.split ( '_' ) + else: + # hidden entry + raise roverlay.config.exceptions.ConfigOptionNotFound ( name ) # --- end of find_config_path (...) --- +def iter_config_keys(): + for key, entry in CONFIG_ENTRY_MAP.items(): + if isinstance ( entry, dict ): + yield key +# --- end of iter_config_keys (...) --- + def _iter_entries(): """Iterates through all entries in CONFIG_ENTRY_MAP and yields config entry information (entry name, description). diff --git a/roverlay/config/exceptions.py b/roverlay/config/exceptions.py new file mode 100644 index 0000000..715d9eb --- /dev/null +++ b/roverlay/config/exceptions.py @@ -0,0 +1,40 @@ +# R overlay -- config package, exceptions +# -*- coding: utf-8 -*- +# Copyright (C) 2014 André Erdmann +# Distributed under the terms of the GNU General Public License; +# either version 2 of the License, or (at your option) any later version. + +__all__ = [ + 'ConfigException', 'ConfigEntryMapException', + 'ConfigKeyError', 'ConfigOptionNotFound', + 'ConfigTreeUsageError', +] + + +class ConfigException ( Exception ): + pass +# --- end of ConfigException --- + +class ConfigEntryMapException ( ConfigException ): + pass +# --- end of ConfigEntryMapException --- + + +class ConfigKeyError ( ConfigException ): + # or inherit KeyError + def __init__ ( self, config_key ): + super ( ConfigKeyError, self ).__init__ ( + "config key {!r} not found but required.".format ( config_key ) + ) +# --- end of ConfigKeyError --- + +class ConfigOptionNotFound ( ConfigException ): + pass +# --- end of ConfigOptionNotFound --- + +class ConfigTreeUsageError ( ConfigException ): + def __init__ ( self, message=None ): + super ( ConfigTreeUsageError, self ).__init__ ( + "bad usage" if message is None else message + ) +# --- end of ConfigTreeUsageError --- diff --git a/roverlay/config/tree.py b/roverlay/config/tree.py index d9f1900..0aeb86c 100644 --- a/roverlay/config/tree.py +++ b/roverlay/config/tree.py @@ -1,6 +1,6 @@ # R overlay -- config package, tree # -*- coding: utf-8 -*- -# Copyright (C) 2012 André Erdmann +# Copyright (C) 2012-2014 André Erdmann # Distributed under the terms of the GNU General Public License; # either version 2 of the License, or (at your option) any later version. @@ -20,9 +20,11 @@ __all__ = [ 'ConfigTree', ] import logging -from roverlay.config import const -from roverlay.config.loader import ConfigLoader -from roverlay.config.util import get_config_path +import roverlay.config.exceptions +from roverlay.config import const +from roverlay.config.loader import ConfigLoader +from roverlay.config.util import get_config_path +from roverlay.config.entryutil import find_config_path CONFIG_INJECTION_IS_BAD = True @@ -115,7 +117,7 @@ class ConfigTree ( object ): pass else: - raise Exception ( "bad usage" ) + raise roverlay.config.exceptions.ConfigUsageError() # --- end of merge_with (...) --- @@ -207,6 +209,9 @@ class ConfigTree ( object ): * key -- * fallback_value -- * fail_if_unset -- fail if key is neither in config nor const + + raises: + * ConfigKeyError -- key does not exist and fail_if_unset is True """ config_value = self._findpath ( key ) @@ -219,7 +224,7 @@ class ConfigTree ( object ): config_value = fallback if config_value is None and fail_if_unset: - raise Exception ( "config key '%s' not found but required." % key ) + raise roverlay.config.exceptions.ConfigKeyError ( key ) return config_value @@ -230,6 +235,81 @@ class ConfigTree ( object ): return self.get ( key, fail_if_unset=True ) # --- end of get_or_fail --- + def get_by_name ( self, option_name, *args, **kwargs ): + """Searches for an option referenced by name (e.g. OVERLAY_DIR) + and returns its value. See ConfigTree.get() for details. + + This is an inefficient operation meant for setup/query scripts. + Use get() where possible. + + arguments: + * option_name + * *args, **kwargs -- passed to get() + + raises: + * ConfigOptionNotFound -- option_name is unknown or hidden + * ConfigEntryMapException -- config entry is broken + * ConfigKeyError -- key does not exist and fail_if_unset is True + """ + return self.get ( find_config_path ( option_name ), *args, **kwargs ) + # --- end of get_by_name (...) --- + + def get_by_name_or_fail ( self, option_name ): + """Alias to self.get_by_name ( key, fail_if_unset=True ).""" + return self.get_by_name ( option_name, fail_if_unset=True ) + # --- end of get_by_name_or_fail (...) --- + + def query_by_name ( self, + request, empty_missing=False, convert_value=None + ): + """Creates a dict of config options, referenced by name + + Returns: 2-tuple ( # of missing options, var dict ). + + arguments: + * request -- an iterable containing strings + or 2-tuples(option_name,var_name) + * empty_missing -- whether to create empty entries for missing options + or not. Defaults to False. + * convert_value -- if set and not None: convert config values using + this function before adding them to the resulting + dict + """ + num_missing = 0 + retvars = dict() + + for k in request: + if ( + not isinstance ( k, str ) and hasattr ( k, '__iter__' ) + and len ( k ) > 1 + ): + + option_name = k[0] + var_name = k[1] + else: + option_name = str(k) + var_name = option_name + # -- end if + + try: + value = self.get_by_name_or_fail ( option_name ) + except ( + roverlay.config.exceptions.ConfigOptionNotFound, + roverlay.config.exceptions.ConfigKeyError + ): + num_missing += 1 + if empty_missing: + retvars [var_name] = "" + else: + if convert_value is not None: + retvars [var_name] = convert_value ( value ) + else: + retvars [var_name] = value + # -- end for + + return ( num_missing, retvars ) + # --- end of query_by_name (...) --- + def get_field_definition ( self, force_update=False ): """Gets the field definition stored in this ConfigTree.