Source code for lib.configuration

from lib.utils import Observable, AbstractPriorityDictionary



[docs]class ConfigurationManager(Observable): """ This object manages sotring and accessing configurations. This object stores individual configurations on a 2-level hierarchy and enables the configurations to be ordered using an arbitary priority system. The 2 levels are named :code:`service_name` and :code:`source_name` to represent the service and the source of the configuration respectively. All configurations under a common :code:`service_name` are agregated using the :class:`ServiceConfigurationWrapper` which allows for easy access to individual configuration items. The priority given to :code:`set_config` is taken to mean that the larger(numerically) the number, the more important it is. So in the case where 2 configurations provide the same key; the configuration with the larger priority number will be used. .. note:: For every successful modification, the observers are notified with 2 parameters: :code:`self` and the *service name* that is affected. .. warning:: A notification of modification may not actually affect the data. :ivar configs: A :code:`dict` storing all the configurations. """ def __init__(self): super(ConfigurationManager, self).__init__() self.configs = {} def __str__(self): import json return json.dumps(self.configs, indent=2) def __repr__(self): return "%s(%s)" % (self.__class__.__name__, str(self))
[docs] def get_config(self, service_name): """ Gets the service's configuration wrapped in a :class:`ServiceConfigurationWrapper`. :param service_name: The name of the service. :return: A read only dictionary like object that manages retrieving the configuration in a transparent manner. """ return ServiceConfigurationWrapper(self, service_name)
[docs] def set_config(self, service_name, source_name, source_priority, new_config): """ Assigns the given configuration to the service's configuration. If there is an existing (:code:`service_name`, :code:`source_name`) pair then it will be overwritten with the values given. The source name can be reused over multiple service names without any ill effects. :param service_name: The name of the service. :param source_name: The name of the source. :param source_priority: The priority of the source. :param new_config: A mapping containing the configuration. """ self.configs.setdefault(service_name, {}) # Setup service name self.configs[service_name][source_name] = {"priority": source_priority, "config": new_config} self._notify_observers(self, service_name)
[docs] def delete_config(self, service_name, source_name=None): """ Removes all configurations under :code:`service_name` and if specified :code:`source_name`. If :code:`source_name` is not specified all configurations a removed. No operation is performed if :code:`service_name` is missing, the same applies if the pair :code:`service_name` and :code:`source_name` are missing. **All** observers are notified if data is removed. :param service_name: The name of the service to remove. :param source_name: The name of source to remove. """ if service_name in self.configs: if source_name is not None: if source_name in self.configs: self.configs[service_name].pop(source_name) else: return # Prevent notification if no op performed. else: self.configs.pop(service_name) self._notify_observers(self, service_name)
[docs]class ServiceConfigurationWrapper(AbstractPriorityDictionary, Observable): """ An immutable dictionary which allows easier access to the values stored in :class:`ConfigurationManager`. It preferable to use :meth:`get_config <ConfigurationManager.get_config>` to create an instance of this class. .. warning:: A notification of modification may not actually affect the data. .. seealso:: :class:`AbstractPriorityDictionary` for more information about the avaliable functions. """ def __init__(self, config_manager, service_name): super(ServiceConfigurationWrapper, self).__init__() self.config_manager = config_manager self.service_name = service_name config_manager.add_observer(self._cfg_mgr_update) def __repr__(self): return "%s(%r, %r)" % (self.__class__.__name__, self.config_manager, self.service_name) def _cfg_mgr_update(self, mgr, service_name=None): """ A callback for configuration manager. This notifies this object's observers if neccissary. """ if service_name is None or service_name == self.service_name: self._notify_observers(self) def _ordered_configs(self): service_config = self.config_manager.configs.get(self.service_name, {}) return map(lambda v: v["config"], sorted(self.service_config().values(), reverse=True, key=lambda v: v["priority"]))