Source code for bastio.configs

# Copyright 2013 Databracket LLC
# See LICENSE file for details.

"""
:module: bastio.configs
:synopsis: Configurations memory and file system store.
:author: Amr Ali <amr@databracket.com>

.. autoclass:: GlobalConfigStore
    :members:
    :special-members:
"""

__author__ = "Amr Ali"
__copyright__ = "Copyright 2013 Databracket LLC"
__license__ = "GPLv3+"

import os
import ConfigParser

from collections import defaultdict

from bastio.mixin import public, UniqueSingletonMeta
from bastio.excepts import BastioConfigError, reraise

@public
[docs]class GlobalConfigStore(defaultdict): """An in-memory configuration store that inherits :class:`defaultdict` behavior. This store is a singleton so only one object is created. Please see :class:`bastio.mixin.UniqueSingletonMeta`. The in-memory store takes precedence over the configuration file. If key was not found in the memory store we'll try to get it from the configuration file, if all fails we will simply return the default value of the ``default_factory`` assigned in the constructor. """ __metaclass__ = UniqueSingletonMeta
[docs] def __init__(self, section='agent', default_factory=str): """ :param section: The section of the configuration file to use by default. :type section: str :param default_factory: See :class:`collections.defaultdict` :type default_factory: object """ super(GlobalConfigStore, self).__init__(default_factory) self.__dict__['_section'] = section self.__dict__['_config'] = None
[docs] def __getattr__(self, attr): """ There's only one case where precedence is reversed in favor of the configuration file; when one of the [method]s below are present right before the <option name>. This and once the value is retrieved successfully it will be set in the memory store so that you can access it later without having to consult the configuration file again. :param attr: The syntax is [method]_[section]_<option name> where [method] and [section] are optional, and <option name> is required. Note that if you wish not to supply [method] you need to remove [section] and ``_`` as well. Also if [section] was not supplied the default section name that was supplied to the constructor will be used. [method] could be one of a few possibilities. Either ``get``, ``getint``, ``getfloat``, or ``getboolean`` that correspond to the methods available through the :class:`ConfigParser` interface. e.g., ``get_alpha_name`` will try to get the option ``name`` from the configuration file, similarly in the case of ``get_name`` we will try to get the option's value from the configuration file but from under the section that was supplied to the constructor. :type attr: str :returns: The option's value or ``default_factory`` if no value was set. :raises: :class:`bastio.excepts.BastioConfigError` """ if attr.startswith('get'): tmp = attr.split('_') method = tmp[0] # Check if config parser is loaded and ready if not self._config: raise BastioConfigError('no configuration file was loaded') # Check if the method requested is supported if not hasattr(self._config, method): raise BastioConfigError('method `{}` is not supported'.format( method)) # Check if <option name> was supplied if len(tmp) < 2: raise BastioConfigError( 'must supply an option name after the method `{}`'.format( method)) # Syntax is now assumed to be [method]_<option name> if len(tmp) == 2: method = tmp[0] option = '_'.join(tmp[1:]) try: self[option] = getattr(self._config, method)(self._section, option) except ConfigParser.NoOptionError: return self[option] except ConfigParser.Error: reraise(BastioConfigError) return self[option] # Handle the case where [section] is also provided if len(tmp) > 2: method = tmp[0] section = tmp[1] option = '_'.join(tmp[2:]) # Treat the rest as the option name try: self[option] = getattr(self._config, method)(section, option) except ConfigParser.NoOptionError: return self[option] except ConfigParser.Error: reraise(BastioConfigError) return self[option] else: if self._config: # Check if it exists in the memory store and if not try the # configuration file if attr in self: return self[attr] # Now let's try the configuration file try: self[attr] = self._config.get(self._section, attr) except ConfigParser.NoOptionError: # Not found here either, return value of ``default_factory`` return self[attr] except ConfigParser.Error: reraise(BastioConfigError) return self[attr]
[docs] def __setattr__(self, attr, value): """Set a value to the in-memory store. :param attr: The key in the key-value in-memory store. :type attr: str :param value: The value in the key-value in-memory store. :type value: object """ self[attr] = value
[docs] def load(self, filename): """Load a configuration file using :class:`ConfigParser` into memory. :param filename: The absolute path of the configuration file. :type filename: str :raises: :class:`bastio.excepts.BastioConfigError` """ if not os.path.exists(filename): raise BastioConfigError( 'configuration file `{}` does not exist'.format(filename)) self.__dict__['_config'] = ConfigParser.SafeConfigParser() ret = self._config.read(filename) if not ret: raise BastioConfigError( 'could not load configuration file: `{}`'.format(filename))

This Page