""" constant.Constants - The simple way to deal with environment constants. """ import os try: import ConfigParser as configparser except ImportError: import configparser import warnings import logging import functools logger = logging.getLogger(__name__) def debug(function): """ logging debug decorator """ @functools.wraps(function) def wrapper(*args, **kvargs): """ wrap method call """ logger.debug('begin %s %s', args, kvargs, extra={'method': function.__name__}) result = function(*args, **kvargs) logger.debug('end %s', result, extra={'method': function.__name__}) return result return wrapper VARIABLE = '__CONSTANTS__' FILENAME = 'constants.ini' class Constants(object): """ Environement sensitive application constants class """ @debug def __init__(self, variable=VARIABLE, filename=FILENAME): """ variable is the name of the environment variable to read the environment / config section from default to __CONSTANTS__ filename is the config filename """ object.__setattr__(self, 'dict', {}) self.variable = variable self.filename = filename self.load() @debug def load(self): """ load the section self.variable from the config file self.filename """ self.get_environment() self.read_config() self.load_dict() @debug def get_environment(self): """ returns the value of the environment variable self.variable """ self.environment = os.environ[self.variable] @debug def read_config(self): """ returns a ConfigParser instance from self.filename """ self.config = configparser.ConfigParser() with open(self.filename) as config_file: self.config.readfp(config_file) @debug def load_dict(self): """ load the config items into self.dict """ self.dict = dict (self.config.items(self.environment)) logger.info('variable: %s, filename: %s, environment: %s, constants: %s', self.variable, self.filename, self.environment, self.dict, extra={'method': 'load'}) @debug def __getitem__(self, item): """ access to environment specific constants in a dictionary manner casts to int, float or keep as string """ return self.cast(self.dict[item]) @debug def __getattr__(self, item): """ syntactic sugar, .item rather than ['item'] """ return self[item] @staticmethod @debug def cast(constant): """ cast string to int, float, eval or keep as string """ if hasattr(constant, 'startswith') and constant.startswith('0') \ and '.' not in constant: return constant try: return int(constant) except ValueError: pass try: return float(constant) except ValueError: pass try: return eval(constant) except (NameError, SyntaxError): pass return constant @debug def __setitem__(self, item, value): """ dict like assignment - warns when a constant is changed """ if item in self.dict: warnings.warn('{0} changed to {1}'.format(item, value)) self.dict[item] = value @debug def __setattr__(self, name, value): """ attribute assignment - warns when a constant is changed """ if hasattr(self, 'dict') and name in self.dict: warnings.warn('{0} changed to {1}'.format(name, value)) self.dict[name] = value else: object.__setattr__(self, name, value)