#!/usr/bin/env python
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Project : Tissu - Functions to handle settings with Fabric
# -----------------------------------------------------------------------------
# License : BSD License
# -----------------------------------------------------------------------------
# Authors : Thierry Stiegler <thierry.stiegler@gmail.com>
# -----------------------------------------------------------------------------
"""
Settings and configuration for your application.
Inspired by the django configuration :
https://github.com/django/django/blob/master/django/conf/__init__.py
Values will be read from the module specified by the TISSU_SETTINGS_MODULE
environment variable, and then from TISSU_GLOBAL_SETTINGS; see the global
settings file for a list of all possible variables.
"""
import os
import re
import time # Needed for Windows
import warnings
import global_settings
import importlib
import tissu.constants as C
ENVIRONMENT_VARIABLE = C.TISSU_SETTINGS_MODULE
empty = object()
[docs]def new_method_proxy(func):
def inner(self, *args):
if self._wrapped is empty:
self._setup()
return func(self._wrapped, *args)
return inner
[docs]class LazyObject(object):
"""
A wrapper for another class that can be used to delay instantiation of the
wrapped class.
By subclassing, you have the opportunity to intercept and alter the
instantiation. If you don't need to do that, use SimpleLazyObject.
"""
def __init__(self):
self._wrapped = empty
__getattr__ = new_method_proxy(getattr)
def __setattr__(self, name, value):
if name == "_wrapped":
# Assign to __dict__ to avoid infinite __setattr__ loops.
self.__dict__["_wrapped"] = value
else:
if self._wrapped is empty:
self._setup()
setattr(self._wrapped, name, value)
def __delattr__(self, name):
if name == "_wrapped":
raise TypeError("can't delete _wrapped.")
if self._wrapped is empty:
self._setup()
delattr(self._wrapped, name)
def _setup(self):
"""
Must be implemented by subclasses to initialise the wrapped object.
"""
raise NotImplementedError
# introspection support:
__members__ = property(lambda self: self.__dir__())
__dir__ = new_method_proxy(dir)
[docs]class LazySettings(LazyObject):
"""
A lazy proxy for either global settings or a custom settings object.
The user can manually configure settings prior to using them. Otherwise,
Tissu uses the settings module pointed to by TISSU_SETTINGS_MODULE.
"""
def _setup(self):
"""
Load the settings module pointed to by the environment variable. This
is used the first time we need any settings at all, if the user has not
previously configured the settings manually.
"""
try:
settings_module = os.environ[ENVIRONMENT_VARIABLE]
if not settings_module: # If it's set but is an empty string.
raise KeyError
except KeyError:
# NOTE: This is arguably an EnvironmentError, but that causes
# problems with Python's interactive help.
raise ImportError("Settings cannot be imported, because environment variable %s is undefined." % ENVIRONMENT_VARIABLE)
self._wrapped = Settings(settings_module)
@property
[docs]class BaseSettings(object):
"""
Common logic for settings whether set by a module or by the user.
"""
def __setattr__(self, name, value):
# some sample in order to handle futur specific syntax for some Change Config keys
#
# if name in ("MEDIA_URL", "STATIC_URL") and value and not value.endswith('/'):
# warnings.warn('If set, %s must end with a slash' % name,
# DeprecationWarning)
object.__setattr__(self, name, value)
[docs]class Settings(BaseSettings):
def __init__(self, settings_module):
# update this dict from global settings (but only for ALL_CAPS settings)
for setting in dir(global_settings):
if setting == setting.upper():
setattr(self, setting, getattr(global_settings, setting))
# store the settings module in case someone later cares
self.SETTINGS_MODULE = settings_module
try:
mod = importlib.import_module(self.SETTINGS_MODULE)
except ImportError, e:
raise ImportError("Could not import settings '%s' (Is it on sys.path?): %s" % (self.SETTINGS_MODULE, e))
for setting in dir(mod):
if setting == setting.upper():
setting_value = getattr(mod, setting)
setattr(self, setting, setting_value)
settings = LazySettings()
# EOF - vim: ts=4 sw=4 noet