Source code for xobox.conf

# -*- coding: utf-8 -*-

"""
    xobox.conf
    ~~~~~~~~~~
    :copyright: Copyright 2017 by the Stormrose Project team, see AUTHORS.
    :license: MIT License, see LICENSE for details.
"""


import configparser
from . import default
from ..utils.dynamic import DynamicIterable
from ..utils.singleton import Singleton


[docs]def get_conf(key): """ Get a global configuration value by its key. :param str key: string identifying the requested configuration value :returns: the requested configuration value or None """ configuration = ApplicationConf.get_instance() if key.upper() in configuration: return configuration[key.upper()] else: return None
@Singleton class ApplicationConf(DynamicIterable): """ Global xobox configuration object. This class acts as a proxy to all configuration information set in :py:mod:`~xobox.conf.default`. The configuration data can be accessed either as :py:func:`property` of the :py:class:`~xobox.conf.ApplicationConf` object, or as *(key, value)* pair via the :py:class:`~xobox.conf.ApplicationConf` dictionary interface. .. note:: Only uppercase configuration values are taken into account. However, when querying for an item, it will also be recognized if it is in lower or mixed case since this class takes care of converting all query keys to upper key before looking for them. Along with each *DEFAULT_...* configuration member, also a corresponding non-default member is created. E. g. alongside with *DEFAULT_CHARSET*, also the non-default *CHARSET* member is created. Other than *DEFAULT_* members, non-default members are mutable, so their values can be updated during runtime. .. note:: Although non-default members are mutable, they cannot be deleted if they belong to a *DEFAULT_* member. Deleting them only resets them to their original DEFAULT value. This class is implemented following the singleton pattern. Therefore, in order to getting a reference to the class' instance, the :py:meth:`~xobox.utils.singleton.Singleton.get_instance` method has to be used. Example:: configuration = ApplicationConf.get_instance() """ def __init__(self): super().__init__() self.register_hook('pre-set', self._hook_uppercase) self.register_hook('pre-get', self._hook_uppercase) self.register_hook('pre-del', self._hook_uppercase) self.register_hook('pre-set', self._hook_defaults_not_mutable) self.register_hook('pre-del', self._hook_defaults_not_mutable) self.register_hook('pre-set', self._hook_default_create_mirror) self.register_hook('pre-del', self._hook_default_mirror_reset) # convert all upper case configuration values from :py:module:`~xobox.conf.default` for setting in dir(default): if setting.isupper(): self[setting] = getattr(default, setting) def _update_from_file(self): """ Update configuration with information from configuration file. Only values will be considered if the appropriate key has been defined in :py:module:`~xobox.conf.default`. Other values are ignored. """ config = configparser.ConfigParser() config.read(self['CONF_FILE']) for sect in config.sections(): for key in config[sect]: if key in self.keys(): self[key] = config[sect][key] @staticmethod def _hook_uppercase(key, value): """ Hook method ensuring that all keys are kept in upper case. To be applied as pre-set, pre-get and pre-del hook. """ return str(key).upper(), value def _hook_defaults_not_mutable(self, key, value): """ Hook method ensuring ``DEFAULT`` values do not get overwritten. To be applied as pre-set and pre-del hook. """ if key.startswith('DEFAULT_') and key in self: raise KeyError('DEFAULT configuration settings are immutable!') return key, value def _hook_default_create_mirror(self, key, value): """ Hook method ensuring for all ``DEFAULT`` values, a mutable mirror is created. To be applied as pre-set hook. """ if key.startswith('DEFAULT_'): self[key[8:]] = value return key, value def _hook_default_mirror_reset(self, key, value): """ Hook method ensuring that mirror values of ``DEFAULT`` entries are reset to their default parent instead of really being deleted. To be applied as pre-del hook. """ if "DEFAULT_{}".format(key) in self: self.__setitem__(key, self["DEFAULT_{}".format(key)]) return None, value else: return key, value