Package turbogears :: Module config

Source Code for Module turbogears.config

  1  """TurboGears configuration""" 
  2   
  3  __all__ = ['update_config', 'get', 'update'] 
  4   
  5  import os, glob, re 
  6   
  7  import cherrypy 
  8  from cherrypy import request, config as cp_config, log as cp_log 
  9  from configobj import ConfigObj 
 10  import pkg_resources 
 11  import logging.handlers 
 12   
 13  # TurboGear's server-side config just points directly to CherryPy. 
 14  server = cp_config 
 15   
 16  # Possible section names for the server-side configuration: 
 17  server_sections = ('DEFAULT', 'global', 'server') 
 18   
 19  # The application config is used when mounting applications. 
 20  # Config values that are not server-wide should be put here. 
 21  app = dict() 
 22   
 23  # Possible section names for the logging configuration: 
 24  logging_sections = ('logging',) 
 25   
 26   
27 -class ConfigError(Exception):
28 """TurboGears configuration error."""
29 30
31 -def _get_formatters(formatters):
32 """Helper function for getting formatters from the logging config.""" 33 for key, formatter in formatters.items(): 34 kw = {} 35 fmt = formatter.get('format', None) 36 if fmt: 37 fmt = fmt.replace('*(', '%(') 38 kw["fmt"] = fmt 39 datefmt = formatter.get('datefmt', None) 40 if datefmt: 41 kw['datefmt'] = datefmt 42 formatter = logging.Formatter(**kw) 43 formatters[key] = formatter
44 45
46 -def _get_handlers(handlers, formatters):
47 """Helper function for getting the handler from the logging config.""" 48 for key, handler in handlers.items(): 49 try: 50 cls = handler.get('class') 51 args = handler.get('args', tuple()) 52 level = handler.get('level', None) 53 try: 54 cls = eval(cls, logging.__dict__) 55 except NameError: 56 try: 57 cls = eval(cls, logging.handlers.__dict__) 58 except NameError, err: 59 raise ConfigError("Specified class in handler %s" 60 " is not a recognizable logger name" % key) 61 try: 62 handler_obj = cls(*eval(args, logging.__dict__)) 63 except IOError, err: 64 raise ConfigError("Missing or wrong argument to %s" 65 " in handler %s -> %s " % (cls.__name__,key,err)) 66 except TypeError, err: 67 raise ConfigError("Wrong format for arguments to %s" 68 " in handler %s -> %s" % (cls.__name__,key,err)) 69 if level: 70 level = eval(level, logging.__dict__) 71 handler_obj.setLevel(level) 72 except KeyError: 73 raise ConfigError("No class specified for logging handler %s" 74 % key) 75 formatter = handler.get('formatter', None) 76 if formatter: 77 try: 78 formatter = formatters[formatter] 79 except KeyError: 80 raise ConfigError("Handler %s references unknown formatter %s" 81 % (key, formatter)) 82 handler_obj.setFormatter(formatter) 83 handlers[key] = handler_obj
84 85
86 -def _get_loggers(loggers, handlers):
87 """Helper function for getting the loggers from the logging config.""" 88 for key, logger in loggers.items(): 89 qualname = logger.get('qualname', None) 90 if qualname: 91 log = logging.getLogger(qualname) 92 else: 93 log = logging.getLogger() 94 95 level = logger.get('level', None) 96 if level: 97 level = eval(level, logging.__dict__) 98 else: 99 level = logging.NOTSET 100 log.setLevel(level) 101 102 propagate = logger.get('propagate', None) 103 if propagate is not None: 104 log.propagate = propagate 105 106 cfghandlers = logger.get('handlers', None) 107 if cfghandlers: 108 if isinstance(cfghandlers, basestring): 109 cfghandlers = [cfghandlers] 110 for handler in cfghandlers: 111 try: 112 handler = handlers[handler] 113 except KeyError: 114 raise ConfigError("Logger %s references unknown handler %s" 115 % (key, handler)) 116 log.addHandler(handler) 117 if qualname == 'cherrypy.error': 118 cp_log.error_log = log 119 elif qualname == 'cherrypy.access': 120 cp_log.access_log = log
121 122
123 -def configure_loggers(logcfg):
124 """Configures the Python logging module. 125 126 We are using options that are very similar to the ones listed in the 127 Python documentation. This also removes the logging configuration from 128 the configuration dictionary because CherryPy doesn't like it there. 129 Here are some of the Python examples converted to the format used here: 130 131 [logging] 132 [[loggers]] 133 [[[parser]]] 134 [logger_parser] 135 level="DEBUG" 136 handlers="hand01" 137 propagate=1 138 qualname="compiler.parser" 139 140 [[handlers]] 141 [[[hand01]]] 142 class="StreamHandler" 143 level="NOTSET" 144 formatter="form01" 145 args="(sys.stdout,)" 146 147 [[formatters]] 148 [[[form01]]] 149 format="F1 *(asctime)s *(levelname)s *(message)s" 150 datefmt= 151 152 One notable format difference is that *() is used in the formatter 153 instead of %() because %() is already used for config file interpolation. 154 155 """ 156 formatters = logcfg.get('formatters', {}) 157 _get_formatters(formatters) 158 159 handlers = logcfg.get('handlers', {}) 160 _get_handlers(handlers, formatters) 161 162 loggers = logcfg.get('loggers', {}) 163 _get_loggers(loggers, handlers)
164 165
166 -def config_defaults():
167 """Return a dict with default global config settings.""" 168 return dict( 169 current_dir_uri=os.path.abspath(os.getcwd()) 170 )
171 172
173 -def config_obj(configfile=None, modulename=None):
174 """Read configuration from given config file and/or module. 175 176 See the docstring of the 'update_config' function for parameter description. 177 178 Returns a config.ConfigObj object. 179 180 """ 181 defaults = config_defaults() 182 183 if modulename: 184 firstdot = modulename.find('.') 185 if firstdot < 0: 186 raise ConfigError('Config file package not specified') 187 lastdot = modulename.rfind('.') 188 top_level_package = modulename[:firstdot] 189 packagename = modulename[:lastdot] 190 modname = modulename[lastdot+1:] 191 modfile = pkg_resources.resource_filename(packagename, modname + '.cfg') 192 if not os.path.exists(modfile): 193 modfile = pkg_resources.resource_filename(packagename, modname) 194 if os.path.isdir(modfile): 195 configfiles = glob.glob(os.path.join(modfile, '*.cfg')) 196 else: 197 configfiles = [modfile] 198 configdata = ConfigObj(unrepr=True) 199 top_level_dir = os.path.normpath(pkg_resources.resource_filename( 200 top_level_package, '')) 201 package_dir = os.path.normpath(pkg_resources.resource_filename( 202 packagename, '')) 203 defaults.update(dict(top_level_dir=top_level_dir, 204 package_dir=package_dir)) 205 configdata.merge(dict(DEFAULT=defaults)) 206 for configfile2 in configfiles: 207 configdata2 = ConfigObj(configfile2, unrepr=True) 208 configdata2.merge(dict(DEFAULT=defaults)) 209 configdata.merge(configdata2) 210 211 if configfile: 212 if modulename: 213 configdata2 = ConfigObj(configfile, unrepr=True) 214 configdata2.merge(dict(DEFAULT=defaults)) 215 configdata.merge(configdata2) 216 else: 217 configdata = ConfigObj(configfile, unrepr=True) 218 return configdata
219 220
221 -def update_config(configfile=None, modulename=None):
222 """Update the system configuration from given config file and/or module. 223 224 'configfile' is a ConfigObj (INI-style) config file, 'modulename' a module 225 path in dotted notation. The function looks for files with a ".cfg" 226 extension if the given module name refers to a package directory or a file 227 with the base name of the right-most part of the module path and a ".cfg" 228 extension added. 229 230 If both 'configfile' and 'modulname' are specified, the module is read 231 first, followed by the config file. This means that the config file's 232 options override the options in the module file. 233 234 """ 235 configdict = config_obj(configfile, modulename).dict() 236 update(configdict)
237 238 239 _obsolete_names = set("""autoreload before_main filters 240 baseurl_filter cache_filter decoding_filter encoding_filter gzip_filter 241 log_debug_info_filter nsgmls_filter response_headers_filter 242 session_authenticate_filter session_auth session_filter 243 static_filter tidy_filter virtual_host_filter wsgiappfilter xmlrpc_filter 244 log_access_file log_file log_to_screen show_tracebacks throw_errors 245 """.split()) 246 247 _tools_names = ('toscawidgets', 'visit') 248
249 -def _check_name(name):
250 """Check name and return translated name where applicable. 251 252 In order to keep the config settings simple and compatible among 253 versions, we hide the fact that some features are currently implemented 254 as CherryPy tools and just silently add settings with the tools prefix. 255 256 """ 257 basename = name.split('.', 1)[0] 258 if basename in _tools_names: 259 return 'tools.' + name 260 elif basename in _obsolete_names: 261 raise KeyError("The config setting %s is obsolete." 262 " Check the CherryPy 3 docs for the new setting." % name)
263 264
265 -def update(configvalues):
266 """Update the configuration with values from a dictionary. 267 268 The values are sent to the appropriate config system 269 (server, app, or logging) automatically. 270 271 """ 272 global server, app 273 274 # Send key values for applications to app, logging to logging, and 275 # the rest to server. app keys are identified by their leading slash. 276 for key, value in configvalues.iteritems(): 277 if not isinstance(key, basestring): 278 raise ValueError("Key error in config update: %r" % key) 279 if key.startswith('/'): 280 if key in app: 281 app[key].update(value) 282 else: 283 app[key] = value 284 mounted_app = cherrypy.tree.apps.get('') 285 if mounted_app: 286 mounted_app.merge({key:value}) 287 elif key in logging_sections: 288 configure_loggers(value) 289 elif key in server_sections and isinstance(value, dict): 290 server.update(value) 291 for key in value: 292 add_key = _check_name(key) 293 if add_key: 294 server[add_key] = value[key] 295 else: 296 server[key] = value 297 add_key = _check_name(key) 298 if add_key: 299 server[add_key] = value
300 301
302 -def get(key, *args):
303 """Get a config setting. 304 305 Uses request.config if available, otherwise defaults back to the 306 server's config settings. 307 308 """ 309 config = getattr(request, 'stage', None) and request.config or server 310 value = config.get(key, *args) 311 if value and key == 'sqlobject.dburi' and os.name == 'nt': 312 value = re.sub('///([A-Za-z]):', r'///\1|', value) 313 return value
314 315
316 -def copy():
317 """Copy server config settings.""" 318 return server.copy()
319 320
321 -def items():
322 """A dict.items() equivalent for config values. 323 324 Returns request specific information if available, otherwise falls back 325 to server config. 326 327 """ 328 if getattr(request, 'stage', None): 329 return request.config.items() 330 else: 331 return server.items()
332