1# -*- coding: utf-8 -*- 2""" 3 webapp2_extras.config 4 ===================== 5 6 Configuration object for webapp2. 7 8 This module is deprecated. See :class:`webapp2.WSGIApplication.config`. 9 10 :copyright: 2011 by tipfy.org. 11 :license: Apache Sotware License, see LICENSE for details. 12""" 13from __future__ import absolute_import 14 15import warnings 16 17import webapp2 18 19warnings.warn(DeprecationWarning( 20 'webapp2_extras.config is deprecated. ' 21 'The WSGIApplication uses webapp2.Config instead.'), 22 stacklevel=1) 23 24#: Value used for missing default values. 25DEFAULT_VALUE = object() 26 27#: Value used for required values. 28REQUIRED_VALUE = object() 29 30 31class Config(dict): 32 """A simple configuration dictionary keyed by module name. This is a 33 dictionary of dictionaries. It requires all values to be dictionaries 34 and applies updates and default values to the inner dictionaries instead 35 of the first level one. 36 37 The configuration object can be set as a ``config`` attribute of 38 :class:`WSGIApplication`:: 39 40 import webapp2 41 from webapp2_extras import config as webapp2_config 42 43 my_config = {} 44 45 my_config['my.module'] = { 46 'foo': 'bar', 47 } 48 49 app = webapp2.WSGIApplication(routes=[ 50 webapp2.Route('/', name='home', handler=MyHandler) 51 ]) 52 app.config = webapp2_config.Config(my_config) 53 54 Then to read configuration values, get them from the app:: 55 56 class MyHandler(RequestHandler): 57 def get(self): 58 foo = self.app.config['my.module']['foo'] 59 60 # ... 61 """ 62 #: Loaded module configurations. 63 loaded = None 64 65 def __init__(self, values=None, defaults=None): 66 """Initializes the configuration object. 67 68 :param values: 69 A dictionary of configuration dictionaries for modules. 70 :param defaults: 71 A dictionary of configuration dictionaries for initial default 72 values. These modules are marked as loaded. 73 """ 74 self.loaded = [] 75 if values is not None: 76 assert isinstance(values, dict) 77 for module, config in values.iteritems(): 78 self.update(module, config) 79 80 if defaults is not None: 81 assert isinstance(defaults, dict) 82 for module, config in defaults.iteritems(): 83 self.setdefault(module, config) 84 self.loaded.append(module) 85 86 def __getitem__(self, module): 87 """Returns the configuration for a module. If it is not already 88 set, loads a ``default_config`` variable from the given module and 89 updates the configuration with those default values 90 91 Every module that allows some kind of configuration sets a 92 ``default_config`` global variable that is loaded by this function, 93 cached and used in case the requested configuration was not defined 94 by the user. 95 96 :param module: 97 The module name. 98 :returns: 99 A configuration value. 100 """ 101 if module not in self.loaded: 102 # Load default configuration and update config. 103 values = webapp2.import_string(module + '.default_config', 104 silent=True) 105 if values: 106 self.setdefault(module, values) 107 108 self.loaded.append(module) 109 110 try: 111 return dict.__getitem__(self, module) 112 except KeyError: 113 raise KeyError('Module %r is not configured.' % module) 114 115 def __setitem__(self, module, values): 116 """Sets a configuration for a module, requiring it to be a dictionary. 117 118 :param module: 119 A module name for the configuration, e.g.: `webapp2.ext.i18n`. 120 :param values: 121 A dictionary of configurations for the module. 122 """ 123 assert isinstance(values, dict), 'Module configuration must be a dict.' 124 dict.__setitem__(self, module, SubConfig(module, values)) 125 126 def get(self, module, default=DEFAULT_VALUE): 127 """Returns a configuration for a module. If default is not provided, 128 returns an empty dict if the module is not configured. 129 130 :param module: 131 The module name. 132 :params default: 133 Default value to return if the module is not configured. If not 134 set, returns an empty dict. 135 :returns: 136 A module configuration. 137 """ 138 if default is DEFAULT_VALUE: 139 default = {} 140 141 return dict.get(self, module, default) 142 143 def setdefault(self, module, values): 144 """Sets a default configuration dictionary for a module. 145 146 :param module: 147 The module to set default configuration, e.g.: `webapp2.ext.i18n`. 148 :param values: 149 A dictionary of configurations for the module. 150 :returns: 151 The module configuration dictionary. 152 """ 153 assert isinstance(values, dict), 'Module configuration must be a dict.' 154 if module not in self: 155 dict.__setitem__(self, module, SubConfig(module)) 156 157 module_dict = dict.__getitem__(self, module) 158 159 for key, value in values.iteritems(): 160 module_dict.setdefault(key, value) 161 162 return module_dict 163 164 def update(self, module, values): 165 """Updates the configuration dictionary for a module. 166 167 :param module: 168 The module to update the configuration, e.g.: `webapp2.ext.i18n`. 169 :param values: 170 A dictionary of configurations for the module. 171 """ 172 assert isinstance(values, dict), 'Module configuration must be a dict.' 173 if module not in self: 174 dict.__setitem__(self, module, SubConfig(module)) 175 176 dict.__getitem__(self, module).update(values) 177 178 def get_config(self, module, key=None, default=REQUIRED_VALUE): 179 """Returns a configuration value for a module and optionally a key. 180 Will raise a KeyError if they the module is not configured or the key 181 doesn't exist and a default is not provided. 182 183 :param module: 184 The module name. 185 :params key: 186 The configuration key. 187 :param default: 188 Default value to return if the key doesn't exist. 189 :returns: 190 A module configuration. 191 """ 192 module_dict = self.__getitem__(module) 193 194 if key is None: 195 return module_dict 196 197 return module_dict.get(key, default) 198 199 200class SubConfig(dict): 201 def __init__(self, module, values=None): 202 dict.__init__(self, values or ()) 203 self.module = module 204 205 def __getitem__(self, key): 206 try: 207 value = dict.__getitem__(self, key) 208 except KeyError: 209 raise KeyError('Module %r does not have the config key %r' % 210 (self.module, key)) 211 212 if value is REQUIRED_VALUE: 213 raise KeyError('Module %r requires the config key %r to be ' 214 'set.' % (self.module, key)) 215 216 return value 217 218 def get(self, key, default=None): 219 if key not in self: 220 value = default 221 else: 222 value = dict.__getitem__(self, key) 223 224 if value is REQUIRED_VALUE: 225 raise KeyError('Module %r requires the config key %r to be ' 226 'set.' % (self.module, key)) 227 228 return value 229