Package turbogears :: Module config

Source Code for Module turbogears.config

  1  import os, glob, re 
  2   
  3  from cherrypy import config 
  4  from configobj import ConfigObj 
  5  import pkg_resources 
  6  import logging.handlers 
  7   
  8  __all__ = ["update_config", "get", "update"] 
  9   
 10   
11 -class ConfigError(Exception):
12 pass
13
14 -def _get_formatters(formatters):
15 for key, formatter in formatters.items(): 16 kw = {} 17 fmt = formatter.get("format", None) 18 if fmt: 19 fmt = fmt.replace("*(", "%(") 20 kw["fmt"] = fmt 21 datefmt = formatter.get("datefmt", None) 22 if datefmt: 23 kw["datefmt"] = datefmt 24 formatter = logging.Formatter(**kw) 25 formatters[key] = formatter
26
27 -def _get_handlers(handlers, formatters):
28 for key, handler in handlers.items(): 29 try: 30 cls = handler.get("class") 31 args = handler.get("args", tuple()) 32 level = handler.get("level", None) 33 try: 34 cls = eval(cls, logging.__dict__) 35 except NameError: 36 try: 37 cls = eval(cls, logging.handlers.__dict__) 38 except NameError, err: 39 raise ConfigError("Specified class in handler " 40 "%s is not a recognizable logger name" % key) 41 try: 42 handler_obj = cls(*eval(args, logging.__dict__)) 43 except IOError,err: 44 raise ConfigError("Missing or wrong argument to " 45 "%s in handler %s -> %s " % (cls.__name__,key,err)) 46 except TypeError,err: 47 raise ConfigError("Wrong format for arguments " 48 "to %s in handler %s -> %s" % (cls.__name__,key,err)) 49 if level: 50 level = eval(level, logging.__dict__) 51 handler_obj.setLevel(level) 52 except KeyError: 53 raise ConfigError("No class specified for logging " 54 "handler %s" % key) 55 formatter = handler.get("formatter", None) 56 if formatter: 57 try: 58 formatter = formatters[formatter] 59 except KeyError: 60 raise ConfigError("Handler %s references unknown " 61 "formatter %s" % (key, formatter)) 62 handler_obj.setFormatter(formatter) 63 handlers[key] = handler_obj
64
65 -def _get_loggers(loggers, handlers):
66 for key, logger in loggers.items(): 67 qualname = logger.get("qualname", None) 68 if qualname: 69 log = logging.getLogger(qualname) 70 else: 71 log = logging.getLogger() 72 73 level = logger.get("level", None) 74 if level: 75 level = eval(level, logging.__dict__) 76 else: 77 level = logging.NOTSET 78 log.setLevel(level) 79 80 propagate = logger.get("propagate", None) 81 if propagate is not None: 82 log.propagate = propagate 83 84 cfghandlers = logger.get("handlers", None) 85 if cfghandlers: 86 if isinstance(cfghandlers, basestring): 87 cfghandlers = [cfghandlers] 88 for handler in cfghandlers: 89 try: 90 handler = handlers[handler] 91 except KeyError: 92 raise ConfigError("Logger %s references unknown " 93 "handler %s" % (key, handler)) 94 log.addHandler(handler)
95
96 -def configure_loggers(config):
97 """Configures the Python logging module. 98 99 We are using options that are very similar to the ones listed in the 100 Python documentation. This also removes the logging configuration from 101 the configuration dictionary because CherryPy doesn't like it there. 102 Here are some of the Python examples converted to the format used here: 103 104 [logging] 105 [[loggers]] 106 [[[parser]]] 107 [logger_parser] 108 level="DEBUG" 109 handlers="hand01" 110 propagate=1 111 qualname="compiler.parser" 112 113 [[handlers]] 114 [[[hand01]]] 115 class="StreamHandler" 116 level="NOTSET" 117 formatter="form01" 118 args="(sys.stdout,)" 119 120 [[formatters]] 121 [[[form01]]] 122 format="F1 *(asctime)s *(levelname)s *(message)s" 123 datefmt= 124 125 One notable format difference is that *() is used in the formatter 126 instead of %() because %() is already used for config file interpolation. 127 128 """ 129 if not config.has_key("logging"): 130 return 131 132 logcfg = config["logging"] 133 formatters = logcfg.get("formatters", {}) 134 _get_formatters(formatters) 135 136 handlers = logcfg.get("handlers", {}) 137 _get_handlers(handlers, formatters) 138 139 loggers = logcfg.get("loggers", {}) 140 _get_loggers(loggers, handlers) 141 142 del config["logging"] 143 config.setdefault("global", {})["tg.new_style_logging"] = True
144 145
146 -def config_defaults():
147 """Return a dict with default global config settings.""" 148 return dict( 149 current_dir_uri = os.path.abspath(os.getcwd()) 150 )
151 152
153 -def config_obj(configfile = None, modulename = None):
154 """Read configuration from given config file and/or module. 155 156 See the docstring of the 'update_config' function for parameter description. 157 158 Returns a config.ConfigObj object. 159 160 """ 161 defaults = config_defaults() 162 163 if modulename: 164 firstdot = modulename.find('.') 165 if firstdot < 0: 166 raise ConfigError('Config file package not specified') 167 lastdot = modulename.rfind('.') 168 top_level_package = modulename[:firstdot] 169 packagename = modulename[:lastdot] 170 modname = modulename[lastdot+1:] 171 modfile = pkg_resources.resource_filename(packagename, 172 modname + '.cfg') 173 if not os.path.exists(modfile): 174 modfile = pkg_resources.resource_filename(packagename, 175 modname) 176 if os.path.isdir(modfile): 177 configfiles = glob.glob(os.path.join(modfile, '*.cfg')) 178 else: 179 configfiles = [modfile] 180 configdata = ConfigObj(unrepr=True) 181 top_level_dir = os.path.normpath(pkg_resources.resource_filename( 182 top_level_package, '')) 183 package_dir = os.path.normpath(pkg_resources.resource_filename( 184 packagename, '')) 185 defaults.update(dict(top_level_dir=top_level_dir, 186 package_dir=package_dir)) 187 configdata.merge(dict(DEFAULT=defaults)) 188 for file in configfiles: 189 configdata2 = ConfigObj(file, unrepr=True) 190 configdata2.merge(dict(DEFAULT=defaults)) 191 configdata.merge(configdata2) 192 193 if configfile: 194 if modulename: 195 configdata2 = ConfigObj(configfile, unrepr=True) 196 configdata2.merge(dict(DEFAULT=defaults)) 197 configdata.merge(configdata2) 198 else: 199 configdata = ConfigObj(configfile, unrepr=True) 200 return configdata
201 202
203 -def update_config(configfile=None, modulename=None):
204 """Update the system configuration from given config file and/or module. 205 206 'configfile' is a ConfigObj (INI-style) config file, 'modulename' a module 207 path in dotted notation. The function looks for files with a ".cfg" 208 extension if the given module name refers to a package directory or a file 209 with the base name of the right-most part of the module path and a ".cfg" 210 extension added. 211 212 If both 'configfile' and 'modulname' are specified, the module is read 213 first, followed by the config file. This means that the config file's 214 options override the options in the module file. 215 216 """ 217 configdict = config_obj(configfile, modulename).dict() 218 configure_loggers(configdict) 219 config.update(configdict)
220 221
222 -def get(key, default_value=None, return_section=False, path=None):
223 """Return config value with setting name given by 'key'. 224 225 If the config setting is unset, return given 'default_value' instead. If 226 'return_section' is specified, return the path to the value, instead of the 227 value itself. If 'path' is specified, return the the value of the setting 228 in the context of the given URL path or below. 229 230 """ 231 value = config.get(key, default_value, return_section, path) 232 if value and key == 'sqlobject.dburi' and os.name == 'nt': 233 value = re.sub('///([A-Za-z]):', r'///\1|', value) 234 return value
235 236
237 -def update(configvalues):
238 """Update the configuration with the values from the dictionary.""" 239 return config.update(configvalues)
240 241
242 -def copy():
243 """Return a copy of config values.""" 244 return config.configMap.copy()
245