From 2611f4e5fd199d6c3b24d212c862ccf03fea93ff Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Tue, 9 Apr 2013 23:52:21 +0900 Subject: add BaseConfig class and its dependencies --- src/leap/common/config/baseconfig.py | 186 +++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 src/leap/common/config/baseconfig.py (limited to 'src/leap/common/config/baseconfig.py') diff --git a/src/leap/common/config/baseconfig.py b/src/leap/common/config/baseconfig.py new file mode 100644 index 0000000..edb9b24 --- /dev/null +++ b/src/leap/common/config/baseconfig.py @@ -0,0 +1,186 @@ +# -*- coding: utf-8 -*- +# baseconfig.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Implements the abstract base class for configuration +""" + +import copy +import logging +import functools +import os + +from abc import ABCMeta, abstractmethod + +from leap.common.check import leap_assert +from leap.common.files import mkdir_p +from leap.common.config.pluggableconfig import PluggableConfig +from leap.common.config.prefixers import get_platform_prefixer + +logger = logging.getLogger(__name__) + + +class BaseConfig: + """ + Abstract base class for any JSON based configuration + """ + + __metaclass__ = ABCMeta + + """ + Standalone is a class wide parameter + + @param standalone: if True it will return the prefix for a + standalone application. Otherwise, it will return the system + default for configuration storage. + @type standalone: bool + """ + standalone = False + + def __init__(self): + self._data = {} + self._config_checker = None + + @abstractmethod + def _get_spec(self): + """ + Returns the spec object for the specific configuration + """ + return None + + def _safe_get_value(self, key): + """ + Tries to return a value only if the config has already been loaded + + @rtype: depends on the config structure, dict, str, array, int + @return: returns the value for the specified key in the config + """ + leap_assert(self._config_checker, "Load the config first") + return self._config_checker.config[key] + + def get_path_prefix(self): + """ + Returns the platform dependant path prefixer + + """ + return get_platform_prefixer().get_path_prefix( + standalone=self.standalone) + + def loaded(self): + """ + Returns True if the configuration has been already + loaded. False otherwise + """ + return self._config_checker is not None + + def save(self, path_list): + """ + Saves the current configuration to disk + + @param path_list: list of components that form the relative + path to configuration. The absolute path will be calculated + depending on the platform. + @type path_list: list + + @return: True if saved to disk correctly, False otherwise + """ + config_path = os.path.join(self.get_path_prefix(), *(path_list[:-1])) + mkdir_p(config_path) + + try: + self._config_checker.serialize(os.path.join(config_path, + path_list[-1])) + except Exception as e: + logger.warning("%s" % (e,)) + raise + return True + + def load(self, path="", data=None, mtime=None): + """ + Loads the configuration from disk + + @type path: str + @param path: relative path to configuration. The absolute path + will be calculated depending on the platform + + @return: True if loaded from disk correctly, False otherwise + """ + + config_path = os.path.join(self.get_path_prefix(), + path) + + self._config_checker = PluggableConfig(format="json") + self._config_checker.options = copy.deepcopy(self._get_spec()) + + try: + if data is None: + self._config_checker.load(fromfile=config_path, mtime=mtime) + else: + self._config_checker.load(data, mtime=mtime) + except Exception as e: + logger.warning("Something went wrong while loading " + + "the config from %s\n%s" % (config_path, e)) + self._config_checker = None + return False + return True + + +class LocalizedKey(object): + """ + Decorator used for keys that are localized in a configuration + """ + + def __init__(self, func, **kwargs): + self._func = func + + def __call__(self, instance, lang="en"): + """ + Tries to return the string for the specified language, otherwise + informs the problem and returns an empty string + + @param lang: language code + @type lang: str + + @return: localized value from the possible values returned by + self._func + """ + descriptions = self._func(instance) + description_lang = "" + config_lang = "en" + for key in descriptions.keys(): + if lang.startswith(key): + config_lang = key + break + + description_lang = descriptions[config_lang] + return description_lang + + def __get__(self, instance, instancetype): + """ + Implement the descriptor protocol to make decorating instance + method possible. + """ + # Return a partial function with the first argument is the instance + # of the class decorated. + return functools.partial(self.__call__, instance) + +if __name__ == "__main__": + try: + config = BaseConfig() # should throw TypeError for _get_spec + except Exception as e: + assert isinstance(e, TypeError), "Something went wrong" + print "Abstract BaseConfig class is working as expected" -- cgit v1.2.3 From f74c32a4a8e9eae9c8055c25d3848ff7d836e308 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 1 May 2013 04:05:03 +0900 Subject: return None if no key found, avoid KeyError --- src/leap/common/config/baseconfig.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/leap/common/config/baseconfig.py') diff --git a/src/leap/common/config/baseconfig.py b/src/leap/common/config/baseconfig.py index edb9b24..146f1e4 100644 --- a/src/leap/common/config/baseconfig.py +++ b/src/leap/common/config/baseconfig.py @@ -70,12 +70,11 @@ class BaseConfig: @return: returns the value for the specified key in the config """ leap_assert(self._config_checker, "Load the config first") - return self._config_checker.config[key] + return self._config_checker.config.get(key, None) def get_path_prefix(self): """ Returns the platform dependant path prefixer - """ return get_platform_prefixer().get_path_prefix( standalone=self.standalone) -- cgit v1.2.3 From 9c12f4cce20ea1dea7e39cda583cb29ded4b4e1a Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 29 May 2013 04:04:14 +0900 Subject: allow absolute paths to config.load --- src/leap/common/config/baseconfig.py | 69 ++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 30 deletions(-) (limited to 'src/leap/common/config/baseconfig.py') diff --git a/src/leap/common/config/baseconfig.py b/src/leap/common/config/baseconfig.py index 146f1e4..2beb4ce 100644 --- a/src/leap/common/config/baseconfig.py +++ b/src/leap/common/config/baseconfig.py @@ -36,18 +36,19 @@ logger = logging.getLogger(__name__) class BaseConfig: """ - Abstract base class for any JSON based configuration + Abstract base class for any JSON based configuration. """ __metaclass__ = ABCMeta """ - Standalone is a class wide parameter + Standalone is a class wide parameter. - @param standalone: if True it will return the prefix for a - standalone application. Otherwise, it will return the system - default for configuration storage. - @type standalone: bool + :param standalone: if True it will return the prefix for a + standalone application. Otherwise, it will + return the system + default for configuration storage. + :type standalone: bool """ standalone = False @@ -58,13 +59,13 @@ class BaseConfig: @abstractmethod def _get_spec(self): """ - Returns the spec object for the specific configuration + Returns the spec object for the specific configuration. """ return None def _safe_get_value(self, key): """ - Tries to return a value only if the config has already been loaded + Tries to return a value only if the config has already been loaded. @rtype: depends on the config structure, dict, str, array, int @return: returns the value for the specified key in the config @@ -88,14 +89,14 @@ class BaseConfig: def save(self, path_list): """ - Saves the current configuration to disk + Saves the current configuration to disk. - @param path_list: list of components that form the relative - path to configuration. The absolute path will be calculated - depending on the platform. - @type path_list: list + :param path_list: list of components that form the relative + path to configuration. The absolute path + will be calculated depending on the platform. + :type path_list: list - @return: True if saved to disk correctly, False otherwise + :return: True if saved to disk correctly, False otherwise """ config_path = os.path.join(self.get_path_prefix(), *(path_list[:-1])) mkdir_p(config_path) @@ -108,19 +109,27 @@ class BaseConfig: raise return True - def load(self, path="", data=None, mtime=None): + def load(self, path="", data=None, mtime=None, relative=True): """ - Loads the configuration from disk + Loads the configuration from disk. - @type path: str - @param path: relative path to configuration. The absolute path - will be calculated depending on the platform + :param path: if relative=True, this is a relative path + to configuration. The absolute path + will be calculated depending on the platform + :type path: str - @return: True if loaded from disk correctly, False otherwise + :param relative: if True, path is relative. If False, it's absolute. + :type relative: bool + + :return: True if loaded from disk correctly, False otherwise + :rtype: bool """ - config_path = os.path.join(self.get_path_prefix(), - path) + if relative is True: + config_path = os.path.join( + self.get_path_prefix(), path) + else: + config_path = path self._config_checker = PluggableConfig(format="json") self._config_checker.options = copy.deepcopy(self._get_spec()) @@ -131,8 +140,8 @@ class BaseConfig: else: self._config_checker.load(data, mtime=mtime) except Exception as e: - logger.warning("Something went wrong while loading " + - "the config from %s\n%s" % (config_path, e)) + logger.error("Something went wrong while loading " + + "the config from %s\n%s" % (config_path, e)) self._config_checker = None return False return True @@ -140,7 +149,7 @@ class BaseConfig: class LocalizedKey(object): """ - Decorator used for keys that are localized in a configuration + Decorator used for keys that are localized in a configuration. """ def __init__(self, func, **kwargs): @@ -149,13 +158,13 @@ class LocalizedKey(object): def __call__(self, instance, lang="en"): """ Tries to return the string for the specified language, otherwise - informs the problem and returns an empty string + informs the problem and returns an empty string. - @param lang: language code - @type lang: str + :param lang: language code + :type lang: str - @return: localized value from the possible values returned by - self._func + :return: localized value from the possible values returned by + self._func """ descriptions = self._func(instance) description_lang = "" -- cgit v1.2.3 From 354467c605f07042568c10c3e931f7fc093c0bf4 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 29 May 2013 05:00:22 +0900 Subject: change docstring comments to use sphinx style --- src/leap/common/config/baseconfig.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/leap/common/config/baseconfig.py') diff --git a/src/leap/common/config/baseconfig.py b/src/leap/common/config/baseconfig.py index 2beb4ce..e6bd9c4 100644 --- a/src/leap/common/config/baseconfig.py +++ b/src/leap/common/config/baseconfig.py @@ -67,8 +67,8 @@ class BaseConfig: """ Tries to return a value only if the config has already been loaded. - @rtype: depends on the config structure, dict, str, array, int - @return: returns the value for the specified key in the config + :rtype: depends on the config structure, dict, str, array, int + :return: returns the value for the specified key in the config """ leap_assert(self._config_checker, "Load the config first") return self._config_checker.config.get(key, None) -- cgit v1.2.3 From 3a4906638909729236b693fb21a4b1b7194344b5 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 27 Jun 2013 15:33:57 -0300 Subject: Bugfix: use the provider's default language as default string Also take care (and note) a possible case with a problematic provider misconfiguration. --- src/leap/common/config/baseconfig.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'src/leap/common/config/baseconfig.py') diff --git a/src/leap/common/config/baseconfig.py b/src/leap/common/config/baseconfig.py index e6bd9c4..699d734 100644 --- a/src/leap/common/config/baseconfig.py +++ b/src/leap/common/config/baseconfig.py @@ -155,26 +155,39 @@ class LocalizedKey(object): def __init__(self, func, **kwargs): self._func = func - def __call__(self, instance, lang="en"): + def __call__(self, instance, lang=None): """ Tries to return the string for the specified language, otherwise - informs the problem and returns an empty string. + returns the default language string. :param lang: language code :type lang: str :return: localized value from the possible values returned by self._func + It returns None in case that the provider does not provides + a matching pair of default_language and string for + that language. + e.g.: + 'default_language': 'es', + 'description': {'en': 'test description'} + Note that the json schema can't check that. """ descriptions = self._func(instance) - description_lang = "" - config_lang = "en" + config_lang = instance.get_default_language() + if lang is None: + lang = config_lang + for key in descriptions.keys(): if lang.startswith(key): config_lang = key break - description_lang = descriptions[config_lang] + description_lang = descriptions.get(config_lang) + if description_lang is None: + logger.error("There is a misconfiguration in the " + "provider's language strings.") + return description_lang def __get__(self, instance, instancetype): -- cgit v1.2.3