1 """Generic configuration system using unrepr.
2
3 Configuration data may be supplied as a Python dictionary, as a filename,
4 or as an open file object. When you supply a filename or file, Python's
5 builtin ConfigParser is used (with some extensions).
6
7 Namespaces
8 ----------
9
10 Configuration keys are separated into namespaces by the first "." in the key.
11
12 The only key that cannot exist in a namespace is the "environment" entry.
13 This special entry 'imports' other config entries from a template stored in
14 the Config.environments dict.
15
16 You can define your own namespaces to be called when new config is merged
17 by adding a named handler to Config.namespaces. The name can be any string,
18 and the handler must be either a callable or a context manager.
19 """
20
21 try:
22
23 from configparser import ConfigParser
24 except ImportError:
25 from ConfigParser import ConfigParser
26
27 try:
28 set
29 except NameError:
30 from sets import Set as set
31
32 try:
33 basestring
34 except NameError:
35 basestring = str
36
37 try:
38
39 import builtins
40 except ImportError:
41
42 import __builtin__ as builtins
43
44 import operator as _operator
45 import sys
46
54
55
57 """A dict of config namespace names and handlers.
58
59 Each config entry should begin with a namespace name; the corresponding
60 namespace handler will be called once for each config entry in that
61 namespace, and will be passed two arguments: the config key (with the
62 namespace removed) and the config value.
63
64 Namespace handlers may be any Python callable; they may also be
65 Python 2.5-style 'context managers', in which case their __enter__
66 method should return a callable to be used as the handler.
67 See cherrypy.tools (the Toolbox class) for an example.
68 """
69
71 """Iterate through config and pass it to each namespace handler.
72
73 config
74 A flat dict, where keys use dots to separate
75 namespaces, and values are arbitrary.
76
77 The first name in each config key is used to look up the corresponding
78 namespace handler. For example, a config entry of {'tools.gzip.on': v}
79 will call the 'tools' namespace handler with the args: ('gzip.on', v)
80 """
81
82 ns_confs = {}
83 for k in config:
84 if "." in k:
85 ns, name = k.split(".", 1)
86 bucket = ns_confs.setdefault(ns, {})
87 bucket[name] = config[k]
88
89
90
91
92
93
94
95 for ns, handler in self.items():
96 exit = getattr(handler, "__exit__", None)
97 if exit:
98 callable = handler.__enter__()
99 no_exc = True
100 try:
101 try:
102 for k, v in ns_confs.get(ns, {}).items():
103 callable(k, v)
104 except:
105
106 no_exc = False
107 if exit is None:
108 raise
109 if not exit(*sys.exc_info()):
110 raise
111
112 finally:
113
114 if no_exc and exit:
115 exit(None, None, None)
116 else:
117 for k, v in ns_confs.get(ns, {}).items():
118 handler(k, v)
119
121 return "%s.%s(%s)" % (self.__module__, self.__class__.__name__,
122 dict.__repr__(self))
123
125 newobj = self.__class__()
126 newobj.update(self)
127 return newobj
128 copy = __copy__
129
130
132 """A dict-like set of configuration data, with defaults and namespaces.
133
134 May take a file, filename, or dict.
135 """
136
137 defaults = {}
138 environments = {}
139 namespaces = NamespaceSet()
140
141 - def __init__(self, file=None, **kwargs):
147
152
164
176
180
181
183 """Sub-class of ConfigParser that keeps the case of options and that
184 raises an exception if the file cannot be read.
185 """
186
189
190 - def read(self, filenames):
203
204 - def as_dict(self, raw=False, vars=None):
205 """Convert an INI file to a dictionary"""
206
207 result = {}
208 for section in self.sections():
209 if section not in result:
210 result[section] = {}
211 for option in self.options(section):
212 value = self.get(section, option, raw=raw, vars=vars)
213 try:
214 value = unrepr(value)
215 except Exception:
216 x = sys.exc_info()[1]
217 msg = ("Config error in section: %r, option: %r, "
218 "value: %r. Config values must be valid Python." %
219 (section, option, value))
220 raise ValueError(msg, x.__class__.__name__, x.args)
221 result[section][option] = value
222 return result
223
225 if hasattr(file, 'read'):
226 self.readfp(file)
227 else:
228 self.read(file)
229 return self.as_dict()
230
231
232
233
234
236
238 m = getattr(self, 'build_' + o.__class__.__name__, None)
239 if m is None:
240 raise TypeError("unrepr does not recognize %s" %
241 repr(o.__class__.__name__))
242 return m(o)
243
245 """Return a Python2 ast Node compiled from a string."""
246 try:
247 import compiler
248 except ImportError:
249
250
251 return eval(s)
252
253 p = compiler.parse("__tempvalue__ = " + s)
254 return p.getChildren()[1].getChildren()[0].getChildren()[1]
255
257 expr, flags, subs = o.getChildren()
258 expr = self.build(expr)
259 subs = self.build(subs)
260 return expr[subs]
261
263 children = map(self.build, o.getChildren())
264 callee = children.pop(0)
265 kwargs = children.pop() or {}
266 starargs = children.pop() or ()
267 args = tuple(children) + tuple(starargs)
268 return callee(*args, **kwargs)
269
271 return map(self.build, o.getChildren())
272
275
277 d = {}
278 i = iter(map(self.build, o.getChildren()))
279 for el in i:
280 d[el] = i.next()
281 return d
282
285
287 name = o.name
288 if name == 'None':
289 return None
290 if name == 'True':
291 return True
292 if name == 'False':
293 return False
294
295
296 try:
297 return modules(name)
298 except ImportError:
299 pass
300
301
302 try:
303 return getattr(builtins, name)
304 except AttributeError:
305 pass
306
307 raise TypeError("unrepr could not resolve the name %s" % repr(name))
308
310 left, right = map(self.build, o.getChildren())
311 return left + right
312
314 left, right = map(self.build, o.getChildren())
315 return left * right
316
318 parent = self.build(o.expr)
319 return getattr(parent, o.attrname)
320
323
325 return -self.build(o.getChildren()[0])
326
328 return self.build(o.getChildren()[0])
329
330
332
334 m = getattr(self, 'build_' + o.__class__.__name__, None)
335 if m is None:
336 raise TypeError("unrepr does not recognize %s" %
337 repr(o.__class__.__name__))
338 return m(o)
339
341 """Return a Python3 ast Node compiled from a string."""
342 try:
343 import ast
344 except ImportError:
345
346
347 return eval(s)
348
349 p = ast.parse("__tempvalue__ = " + s)
350 return p.body[0].value
351
353 return self.build(o.value)[self.build(o.slice)]
354
356 return self.build(o.value)
357
359 callee = self.build(o.func)
360
361 if o.args is None:
362 args = ()
363 else:
364 args = tuple([self.build(a) for a in o.args])
365
366 if o.starargs is None:
367 starargs = ()
368 else:
369 starargs = self.build(o.starargs)
370
371 if o.kwargs is None:
372 kwargs = {}
373 else:
374 kwargs = self.build(o.kwargs)
375
376 return callee(*(args + starargs), **kwargs)
377
379 return list(map(self.build, o.elts))
380
383
386
390
393
395 name = o.id
396 if name == 'None':
397 return None
398 if name == 'True':
399 return True
400 if name == 'False':
401 return False
402
403
404 try:
405 return modules(name)
406 except ImportError:
407 pass
408
409
410 try:
411 import builtins
412 return getattr(builtins, name)
413 except AttributeError:
414 pass
415
416 raise TypeError("unrepr could not resolve the name %s" % repr(name))
417
419 op, operand = map(self.build, [o.op, o.operand])
420 return op(operand)
421
423 left, op, right = map(self.build, [o.left, o.op, o.right])
424 return op(left, right)
425
428
431
434
436 parent = self.build(o.value)
437 return getattr(parent, o.attr)
438
441
442
444 """Return a Python object compiled from a string."""
445 if not s:
446 return s
447 if sys.version_info < (3, 0):
448 b = _Builder2()
449 else:
450 b = _Builder3()
451 obj = b.astnode(s)
452 return b.build(obj)
453
454
456 """Load a module and retrieve a reference to that module."""
457 try:
458 mod = sys.modules[modulePath]
459 if mod is None:
460 raise KeyError()
461 except KeyError:
462
463 mod = __import__(modulePath, globals(), locals(), [''])
464 return mod
465
467 """Load a module and retrieve an attribute of that module."""
468
469
470 last_dot = full_attribute_name.rfind(".")
471 attr_name = full_attribute_name[last_dot + 1:]
472 mod_path = full_attribute_name[:last_dot]
473
474 mod = modules(mod_path)
475
476 try:
477 attr = getattr(mod, attr_name)
478 except AttributeError:
479 raise AttributeError("'%s' object has no attribute '%s'"
480 % (mod_path, attr_name))
481
482
483 return attr
484