1 | from django.utils.functional import memoize
|
---|
2 | from django.core.exceptions import ImproperlyConfigured
|
---|
3 |
|
---|
4 | __all__ = ['RequiredSetting', 'FromSetting', 'ComputedSetting', 'AppSettings']
|
---|
5 |
|
---|
6 | class SpecialConf(object):
|
---|
7 | """
|
---|
8 | Base for classes defining special configuration options
|
---|
9 | The interface is simple: get_value(name) will be called if
|
---|
10 | no value was supplied for the setting by the user
|
---|
11 | """
|
---|
12 | def get_value(self, name):
|
---|
13 | raise NotImplementedError
|
---|
14 |
|
---|
15 | def set_settings_object(self, obj):
|
---|
16 | self.settings_object = obj
|
---|
17 |
|
---|
18 | class RequiredSetting(SpecialConf):
|
---|
19 | "Just to mark a setting as required"
|
---|
20 | def get_value(self, name):
|
---|
21 | raise ImproperlyConfigured, "%s setting is missing" % name
|
---|
22 |
|
---|
23 | class FromSetting(SpecialConf):
|
---|
24 | "Take default value from another setting"
|
---|
25 | def __init__(self, source):
|
---|
26 | self.source = source
|
---|
27 | def get_value(self, name):
|
---|
28 | return getattr(self.settings_object, self.source)
|
---|
29 |
|
---|
30 | class ComputedSetting(SpecialConf):
|
---|
31 | """
|
---|
32 | Compute default from a set of other settings.
|
---|
33 |
|
---|
34 | Initialized with a function, a sequence of settings names, and optional
|
---|
35 | additional (constant) arguments and keyword arguments. The default for
|
---|
36 | the setting will be computed (only if needed) by calling the function
|
---|
37 | with the setting values as first positional arguments, followed by
|
---|
38 |
|
---|
39 | """
|
---|
40 | def __init__(self, func, sources, *args, **kwargs):
|
---|
41 | self.func = func
|
---|
42 | if isinstance(sources, basestring): sources = (sources,)
|
---|
43 | self.sources = sources
|
---|
44 | self.args = args
|
---|
45 | self.kwargs = kwargs
|
---|
46 | def get_value(self, name):
|
---|
47 | sources = [getattr(self.settings_object, s) for s in self.sources]
|
---|
48 | sources.extend(self.args)
|
---|
49 | return self.func(*sources, **self.kwargs)
|
---|
50 |
|
---|
51 |
|
---|
52 |
|
---|
53 | class SettingProperty(object):
|
---|
54 |
|
---|
55 | def __init__(self, name, default, cache):
|
---|
56 | self.name = name
|
---|
57 | self.default = default
|
---|
58 | self.getter = memoize(self.get_conf_value, cache, 1)
|
---|
59 |
|
---|
60 | def __get__(self, settings_object, type=None):
|
---|
61 | return self.getter(self.name, self.default, settings_object)
|
---|
62 |
|
---|
63 | @staticmethod
|
---|
64 | def get_conf_value(name, default, settings_object):
|
---|
65 | # First look in the project settings file
|
---|
66 | from django.conf import settings
|
---|
67 | value = getattr(settings, name, default)
|
---|
68 | if isinstance(value, SpecialConf):
|
---|
69 | # Special settings may want to use other settings from the settings_object
|
---|
70 | value.set_settings_object(settings_object)
|
---|
71 | value = value.get_value(name)
|
---|
72 | return value
|
---|
73 |
|
---|
74 | class SettingsMetaClass(type):
|
---|
75 |
|
---|
76 | def __new__(meta, name, bases, namespace):
|
---|
77 | # turn all all-caps names into settings
|
---|
78 | cache = {}
|
---|
79 | for n, v in namespace.items():
|
---|
80 | if n==n.upper():
|
---|
81 | namespace[n] = SettingProperty(n, v, cache)
|
---|
82 | return super(SettingsMetaClass, meta).__new__(meta, name, bases, namespace)
|
---|
83 |
|
---|
84 | class AppSettings(object):
|
---|
85 |
|
---|
86 | __metaclass__ = SettingsMetaClass
|
---|
87 |
|
---|
88 | def __getattr__(self, name):
|
---|
89 | # for names not in our class
|
---|
90 | from django.conf import settings
|
---|
91 | return getattr(settings, name)
|
---|
92 |
|
---|