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 EEBCC13894A for ; Sat, 9 Feb 2013 20:45:34 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 3C45F21C04B; Sat, 9 Feb 2013 20:45:34 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 7054F21C036 for ; Sat, 9 Feb 2013 20:45:33 +0000 (UTC) Received: from hornbill.gentoo.org (hornbill.gentoo.org [94.100.119.163]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 4B2F833E386 for ; Sat, 9 Feb 2013 20:45:32 +0000 (UTC) Received: from localhost.localdomain (localhost [127.0.0.1]) by hornbill.gentoo.org (Postfix) with ESMTP id 98F25E4090 for ; Sat, 9 Feb 2013 20:45:29 +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: <1360440495.73a23ab7ced4890b5930ff27cc2a4759f3956594.dywi@gentoo> Subject: [gentoo-commits] proj/R_overlay:master commit in: roverlay/config/ X-VCS-Repository: proj/R_overlay X-VCS-Files: roverlay/config/loader.py X-VCS-Directories: roverlay/config/ X-VCS-Committer: dywi X-VCS-Committer-Name: André Erdmann X-VCS-Revision: 73a23ab7ced4890b5930ff27cc2a4759f3956594 X-VCS-Branch: master Date: Sat, 9 Feb 2013 20:45:29 +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: e482bec2-cce9-447e-a767-abab9da81306 X-Archives-Hash: cb6e685bbf5310d6b0434a8574978a53 commit: 73a23ab7ced4890b5930ff27cc2a4759f3956594 Author: André Erdmann mailerd de> AuthorDate: Sat Feb 9 19:20:16 2013 +0000 Commit: André Erdmann mailerd de> CommitDate: Sat Feb 9 20:08:15 2013 +0000 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=73a23ab7 config/loader: list of choices, value functions * added the ability to load a "list of choices" example config_entry_map entry << config_option = dict ( value_type = "list", choices = frozenset (( "first", "second", )), ) >> * added the ability to convert values after validating their value_type via 'f_convert' and 'f_convert_item' in the config entry dict * added the ability to verify the (final) value of a config option via 'f_verify' in the config entry dict --- roverlay/config/loader.py | 144 +++++++++++++++++++++++++++++++++++---------- 1 files changed, 113 insertions(+), 31 deletions(-) diff --git a/roverlay/config/loader.py b/roverlay/config/loader.py index e71770b..71f4074 100644 --- a/roverlay/config/loader.py +++ b/roverlay/config/loader.py @@ -22,6 +22,10 @@ from roverlay.config import fielddef from roverlay.config.util import get_config_path from roverlay.config.entrymap import CONFIG_ENTRY_MAP +def listlike ( var ): + return hasattr ( var, '__iter__' ) and not isinstance ( var, str ) +# --- end of listlike (...) --- + class ConfigLoader ( object ): """Loads config data from files.""" @@ -73,41 +77,122 @@ class ConfigLoader ( object ): * value -- value read from a config file (will be verified here) * config_root -- ignored; """ - # determine the config path - path = None - if 'path' in cref: - path = cref ['path'] - else: - path = option.split ( '_' ) + def uppercase_if_in_iterable ( s, iterable ): + """Returns s.upper() if s.upper() in iterable else None. - path = get_config_path ( path ) + arguments: + * s -- string + * iterable -- items + """ + s_up = s.upper() + return s_up if s_up in iterable else None + # --- end of uppercase_if_in_iterable (...) --- + + # determine the config path + path = get_config_path ( + cref.get ( "path", None ) or option.split ( '_' ) + ) # need a valid path if path: # verify and convert value if value_type is set - if 'value_type' in cref and cref ['value_type']: + if cref.get ( "value_type", None ): value = self._make_and_verify_value ( cref ['value_type'], value ) - - if 'choices' in cref and value not in cref ['choices']: - if 'flags' in cref and 'CAPSLOCK' in cref ['flags']: - v_up = value.upper() - value = v_up if v_up in cref ['choices'] else None - else: + # --- end prepare value; + + value_choices = cref.get ( "choices", None ) + + if value_choices: + if listlike ( value ): + + # create value_invalid for logging + # * also used as condition whether value is valid or not + value_invalid = None + + if 'flags' in cref and 'CAPSLOCK' in cref ['flags']: + value_valid = list ( + filter ( + None, + ( + uppercase_if_in_iterable ( v, value_choices ) + for v in value + ) + ) + ) + + if len ( value_valid ) != len ( value ): + + value_invalid = [ + v for v in value if v.upper() not in value_choices + ] + else: + value_valid = [ v for v in value if v in value_choices ] + + if len ( value_valid ) != len ( value ): + value_invalid = [ + v for v in value if v not in value_choices + ] + + + if not value_invalid: + value = value_valid + else: + # mark value as invalid + self.logger.error ( + "Option {o!r} has unusable value(s): {v!r}.".format ( + o=option, + v=', '.join ( value_invalid ) + ) + ) + #value = None + # return immediately, no need to log about that twice + return False + + + elif 'flags' in cref and 'CAPSLOCK' in cref ['flags']: + value = uppercase_if_in_iterable ( value, value_choices ) + + elif value not in value_choices: value = None + # else value is valid + elif 'flags' in cref and 'CAPSLOCK' in cref ['flags']: - value = value.upper() + if listlike ( value ): + value = [ s.upper() for s in value ] + # is a list + pass + else: + value = value.upper() + # --- end verify choices / apply flags; # need a valid value if value is not None: - self.logger.debug ( - "New config entry %s with path %s and value %s." % - ( option, path, value ) + if listlike ( value ) and 'f_convert_item' in cref: + # or use map() + value = [ cref ['f_convert_item'] ( v ) for v in value ] + + # not elif (use both functions for iterables if specified) + if 'f_convert' in cref: + # func should expect an iterable if value_type has/is "list" + value = cref ['f_convert'] ( value ) + + if value is not None and ( + 'f_verify' not in cref + or cref ['f_verify'] ( + value, + logger=self.logger.getChild ( option ) ) + ): + + self.logger.debug ( + "New config entry {o} with path {p} and value {v}.".format ( + o=option, p=path, v=value + ) ) # add option/value to the config self._setval ( path, value ) @@ -115,9 +200,9 @@ class ConfigLoader ( object ): return True else: self.logger.error ( - "Option '%s' has an unusable value '%s'." % - ( option, value ) - ) + "Option {o!r} has an unusable value {v!r}.".format ( + o=option, v=value + ) ) return False # --- # --- end of _config_enty (...) --- @@ -161,15 +246,11 @@ class ConfigLoader ( object ): raise Exception ( "CONFIG_ENTRY_MAP is invalid!" ) # check if config entry is disabled - if cref is None: + if cref is not None: + return self._config_entry ( cref, option, value, config_root ) + else: # deftly ignored return True - - elif self._config_entry ( cref, option, value, config_root ): - return True - else: - self.logger.error ( "Option '%s' is unusable..." % real_option ) - return False # --- self.logger.warning ( "Option '%s' is unknown." % real_option ) @@ -210,12 +291,13 @@ class ConfigLoader ( object ): option, equal, value = nextline () - if fh: - fh.close () - except IOError as ioerr: raise + finally: + if 'fh' in locals() and fh: + fh.close() + # --- end of load_config (...) --- def load_field_definition ( self, def_file, lenient=False ):