Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(402)

Side by Side Diff: third_party/cherrypy/lib/reprconf.py

Issue 9368042: Add CherryPy to third_party. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build/
Patch Set: '' Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/cherrypy/lib/profiler.py ('k') | third_party/cherrypy/lib/sessions.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
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 # Python 3.0+
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 # Python 3
39 import builtins
40 except ImportError:
41 # Python 2
42 import __builtin__ as builtins
43
44 import operator as _operator
45 import sys
46
47 def as_dict(config):
48 """Return a dict from 'config' whether it is a dict, file, or filename."""
49 if isinstance(config, basestring):
50 config = Parser().dict_from_file(config)
51 elif hasattr(config, 'read'):
52 config = Parser().dict_from_file(config)
53 return config
54
55
56 class NamespaceSet(dict):
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
70 def __call__(self, config):
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 # Separate the given config into namespaces
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 # I chose __enter__ and __exit__ so someday this could be
90 # rewritten using Python 2.5's 'with' statement:
91 # for ns, handler in self.iteritems():
92 # with handler as callable:
93 # for k, v in ns_confs.get(ns, {}).iteritems():
94 # callable(k, v)
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 # The exceptional case is handled here
106 no_exc = False
107 if exit is None:
108 raise
109 if not exit(*sys.exc_info()):
110 raise
111 # The exception is swallowed if exit() returns true
112 finally:
113 # The normal and non-local-goto cases are handled here
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
120 def __repr__(self):
121 return "%s.%s(%s)" % (self.__module__, self.__class__.__name__,
122 dict.__repr__(self))
123
124 def __copy__(self):
125 newobj = self.__class__()
126 newobj.update(self)
127 return newobj
128 copy = __copy__
129
130
131 class Config(dict):
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):
142 self.reset()
143 if file is not None:
144 self.update(file)
145 if kwargs:
146 self.update(kwargs)
147
148 def reset(self):
149 """Reset self to default values."""
150 self.clear()
151 dict.update(self, self.defaults)
152
153 def update(self, config):
154 """Update self from a dict, file or filename."""
155 if isinstance(config, basestring):
156 # Filename
157 config = Parser().dict_from_file(config)
158 elif hasattr(config, 'read'):
159 # Open file object
160 config = Parser().dict_from_file(config)
161 else:
162 config = config.copy()
163 self._apply(config)
164
165 def _apply(self, config):
166 """Update self from a dict."""
167 which_env = config.get('environment')
168 if which_env:
169 env = self.environments[which_env]
170 for k in env:
171 if k not in config:
172 config[k] = env[k]
173
174 dict.update(self, config)
175 self.namespaces(config)
176
177 def __setitem__(self, k, v):
178 dict.__setitem__(self, k, v)
179 self.namespaces({k: v})
180
181
182 class Parser(ConfigParser):
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
187 def optionxform(self, optionstr):
188 return optionstr
189
190 def read(self, filenames):
191 if isinstance(filenames, basestring):
192 filenames = [filenames]
193 for filename in filenames:
194 # try:
195 # fp = open(filename)
196 # except IOError:
197 # continue
198 fp = open(filename)
199 try:
200 self._read(fp, filename)
201 finally:
202 fp.close()
203
204 def as_dict(self, raw=False, vars=None):
205 """Convert an INI file to a dictionary"""
206 # Load INI file into a dict
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
224 def dict_from_file(self, file):
225 if hasattr(file, 'read'):
226 self.readfp(file)
227 else:
228 self.read(file)
229 return self.as_dict()
230
231
232 # public domain "unrepr" implementation, found on the web and then improved.
233
234
235 class _Builder2:
236
237 def build(self, o):
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
244 def astnode(self, s):
245 """Return a Python2 ast Node compiled from a string."""
246 try:
247 import compiler
248 except ImportError:
249 # Fallback to eval when compiler package is not available,
250 # e.g. IronPython 1.0.
251 return eval(s)
252
253 p = compiler.parse("__tempvalue__ = " + s)
254 return p.getChildren()[1].getChildren()[0].getChildren()[1]
255
256 def build_Subscript(self, o):
257 expr, flags, subs = o.getChildren()
258 expr = self.build(expr)
259 subs = self.build(subs)
260 return expr[subs]
261
262 def build_CallFunc(self, o):
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
270 def build_List(self, o):
271 return map(self.build, o.getChildren())
272
273 def build_Const(self, o):
274 return o.value
275
276 def build_Dict(self, o):
277 d = {}
278 i = iter(map(self.build, o.getChildren()))
279 for el in i:
280 d[el] = i.next()
281 return d
282
283 def build_Tuple(self, o):
284 return tuple(self.build_List(o))
285
286 def build_Name(self, o):
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 # See if the Name is a package or module. If it is, import it.
296 try:
297 return modules(name)
298 except ImportError:
299 pass
300
301 # See if the Name is in builtins.
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
309 def build_Add(self, o):
310 left, right = map(self.build, o.getChildren())
311 return left + right
312
313 def build_Mul(self, o):
314 left, right = map(self.build, o.getChildren())
315 return left * right
316
317 def build_Getattr(self, o):
318 parent = self.build(o.expr)
319 return getattr(parent, o.attrname)
320
321 def build_NoneType(self, o):
322 return None
323
324 def build_UnarySub(self, o):
325 return -self.build(o.getChildren()[0])
326
327 def build_UnaryAdd(self, o):
328 return self.build(o.getChildren()[0])
329
330
331 class _Builder3:
332
333 def build(self, o):
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
340 def astnode(self, s):
341 """Return a Python3 ast Node compiled from a string."""
342 try:
343 import ast
344 except ImportError:
345 # Fallback to eval when ast package is not available,
346 # e.g. IronPython 1.0.
347 return eval(s)
348
349 p = ast.parse("__tempvalue__ = " + s)
350 return p.body[0].value
351
352 def build_Subscript(self, o):
353 return self.build(o.value)[self.build(o.slice)]
354
355 def build_Index(self, o):
356 return self.build(o.value)
357
358 def build_Call(self, o):
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
378 def build_List(self, o):
379 return list(map(self.build, o.elts))
380
381 def build_Str(self, o):
382 return o.s
383
384 def build_Num(self, o):
385 return o.n
386
387 def build_Dict(self, o):
388 return dict([(self.build(k), self.build(v))
389 for k, v in zip(o.keys, o.values)])
390
391 def build_Tuple(self, o):
392 return tuple(self.build_List(o))
393
394 def build_Name(self, o):
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 # See if the Name is a package or module. If it is, import it.
404 try:
405 return modules(name)
406 except ImportError:
407 pass
408
409 # See if the Name is in builtins.
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
418 def build_UnaryOp(self, o):
419 op, operand = map(self.build, [o.op, o.operand])
420 return op(operand)
421
422 def build_BinOp(self, o):
423 left, op, right = map(self.build, [o.left, o.op, o.right])
424 return op(left, right)
425
426 def build_Add(self, o):
427 return _operator.add
428
429 def build_Mult(self, o):
430 return _operator.mul
431
432 def build_USub(self, o):
433 return _operator.neg
434
435 def build_Attribute(self, o):
436 parent = self.build(o.value)
437 return getattr(parent, o.attr)
438
439 def build_NoneType(self, o):
440 return None
441
442
443 def unrepr(s):
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
455 def modules(modulePath):
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 # The last [''] is important.
463 mod = __import__(modulePath, globals(), locals(), [''])
464 return mod
465
466 def attributes(full_attribute_name):
467 """Load a module and retrieve an attribute of that module."""
468
469 # Parse out the path, module, and attribute
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 # Let an AttributeError propagate outward.
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 # Return a reference to the attribute.
483 return attr
484
485
OLDNEW
« no previous file with comments | « third_party/cherrypy/lib/profiler.py ('k') | third_party/cherrypy/lib/sessions.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698