summaryrefslogtreecommitdiff
path: root/vendor/CherryPy-3.2.0/py2/cherrypy/lib/reprconf.py
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/CherryPy-3.2.0/py2/cherrypy/lib/reprconf.py')
-rw-r--r--vendor/CherryPy-3.2.0/py2/cherrypy/lib/reprconf.py351
1 files changed, 351 insertions, 0 deletions
diff --git a/vendor/CherryPy-3.2.0/py2/cherrypy/lib/reprconf.py b/vendor/CherryPy-3.2.0/py2/cherrypy/lib/reprconf.py
new file mode 100644
index 0000000..e18949e
--- /dev/null
+++ b/vendor/CherryPy-3.2.0/py2/cherrypy/lib/reprconf.py
@@ -0,0 +1,351 @@
+"""Generic configuration system using unrepr.
+
+Configuration data may be supplied as a Python dictionary, as a filename,
+or as an open file object. When you supply a filename or file, Python's
+builtin ConfigParser is used (with some extensions).
+
+Namespaces
+----------
+
+Configuration keys are separated into namespaces by the first "." in the key.
+
+The only key that cannot exist in a namespace is the "environment" entry.
+This special entry 'imports' other config entries from a template stored in
+the Config.environments dict.
+
+You can define your own namespaces to be called when new config is merged
+by adding a named handler to Config.namespaces. The name can be any string,
+and the handler must be either a callable or a context manager.
+"""
+
+try:
+ # Python 3.0+
+ from configparser import ConfigParser
+except ImportError:
+ from ConfigParser import ConfigParser
+
+try:
+ set
+except NameError:
+ from sets import Set as set
+import sys
+
+def as_dict(config):
+ """Return a dict from 'config' whether it is a dict, file, or filename."""
+ if isinstance(config, basestring):
+ config = Parser().dict_from_file(config)
+ elif hasattr(config, 'read'):
+ config = Parser().dict_from_file(config)
+ return config
+
+
+class NamespaceSet(dict):
+ """A dict of config namespace names and handlers.
+
+ Each config entry should begin with a namespace name; the corresponding
+ namespace handler will be called once for each config entry in that
+ namespace, and will be passed two arguments: the config key (with the
+ namespace removed) and the config value.
+
+ Namespace handlers may be any Python callable; they may also be
+ Python 2.5-style 'context managers', in which case their __enter__
+ method should return a callable to be used as the handler.
+ See cherrypy.tools (the Toolbox class) for an example.
+ """
+
+ def __call__(self, config):
+ """Iterate through config and pass it to each namespace handler.
+
+ config
+ A flat dict, where keys use dots to separate
+ namespaces, and values are arbitrary.
+
+ The first name in each config key is used to look up the corresponding
+ namespace handler. For example, a config entry of {'tools.gzip.on': v}
+ will call the 'tools' namespace handler with the args: ('gzip.on', v)
+ """
+ # Separate the given config into namespaces
+ ns_confs = {}
+ for k in config:
+ if "." in k:
+ ns, name = k.split(".", 1)
+ bucket = ns_confs.setdefault(ns, {})
+ bucket[name] = config[k]
+
+ # I chose __enter__ and __exit__ so someday this could be
+ # rewritten using Python 2.5's 'with' statement:
+ # for ns, handler in self.iteritems():
+ # with handler as callable:
+ # for k, v in ns_confs.get(ns, {}).iteritems():
+ # callable(k, v)
+ for ns, handler in self.items():
+ exit = getattr(handler, "__exit__", None)
+ if exit:
+ callable = handler.__enter__()
+ no_exc = True
+ try:
+ try:
+ for k, v in ns_confs.get(ns, {}).items():
+ callable(k, v)
+ except:
+ # The exceptional case is handled here
+ no_exc = False
+ if exit is None:
+ raise
+ if not exit(*sys.exc_info()):
+ raise
+ # The exception is swallowed if exit() returns true
+ finally:
+ # The normal and non-local-goto cases are handled here
+ if no_exc and exit:
+ exit(None, None, None)
+ else:
+ for k, v in ns_confs.get(ns, {}).items():
+ handler(k, v)
+
+ def __repr__(self):
+ return "%s.%s(%s)" % (self.__module__, self.__class__.__name__,
+ dict.__repr__(self))
+
+ def __copy__(self):
+ newobj = self.__class__()
+ newobj.update(self)
+ return newobj
+ copy = __copy__
+
+
+class Config(dict):
+ """A dict-like set of configuration data, with defaults and namespaces.
+
+ May take a file, filename, or dict.
+ """
+
+ defaults = {}
+ environments = {}
+ namespaces = NamespaceSet()
+
+ def __init__(self, file=None, **kwargs):
+ self.reset()
+ if file is not None:
+ self.update(file)
+ if kwargs:
+ self.update(kwargs)
+
+ def reset(self):
+ """Reset self to default values."""
+ self.clear()
+ dict.update(self, self.defaults)
+
+ def update(self, config):
+ """Update self from a dict, file or filename."""
+ if isinstance(config, basestring):
+ # Filename
+ config = Parser().dict_from_file(config)
+ elif hasattr(config, 'read'):
+ # Open file object
+ config = Parser().dict_from_file(config)
+ else:
+ config = config.copy()
+ self._apply(config)
+
+ def _apply(self, config):
+ """Update self from a dict."""
+ which_env = config.get('environment')
+ if which_env:
+ env = self.environments[which_env]
+ for k in env:
+ if k not in config:
+ config[k] = env[k]
+
+ dict.update(self, config)
+ self.namespaces(config)
+
+ def __setitem__(self, k, v):
+ dict.__setitem__(self, k, v)
+ self.namespaces({k: v})
+
+
+class Parser(ConfigParser):
+ """Sub-class of ConfigParser that keeps the case of options and that
+ raises an exception if the file cannot be read.
+ """
+
+ def optionxform(self, optionstr):
+ return optionstr
+
+ def read(self, filenames):
+ if isinstance(filenames, basestring):
+ filenames = [filenames]
+ for filename in filenames:
+ # try:
+ # fp = open(filename)
+ # except IOError:
+ # continue
+ fp = open(filename)
+ try:
+ self._read(fp, filename)
+ finally:
+ fp.close()
+
+ def as_dict(self, raw=False, vars=None):
+ """Convert an INI file to a dictionary"""
+ # Load INI file into a dict
+ result = {}
+ for section in self.sections():
+ if section not in result:
+ result[section] = {}
+ for option in self.options(section):
+ value = self.get(section, option, raw, vars)
+ try:
+ value = unrepr(value)
+ except Exception, x:
+ msg = ("Config error in section: %r, option: %r, "
+ "value: %r. Config values must be valid Python." %
+ (section, option, value))
+ raise ValueError(msg, x.__class__.__name__, x.args)
+ result[section][option] = value
+ return result
+
+ def dict_from_file(self, file):
+ if hasattr(file, 'read'):
+ self.readfp(file)
+ else:
+ self.read(file)
+ return self.as_dict()
+
+
+# public domain "unrepr" implementation, found on the web and then improved.
+
+class _Builder:
+
+ def build(self, o):
+ m = getattr(self, 'build_' + o.__class__.__name__, None)
+ if m is None:
+ raise TypeError("unrepr does not recognize %s" %
+ repr(o.__class__.__name__))
+ return m(o)
+
+ def build_Subscript(self, o):
+ expr, flags, subs = o.getChildren()
+ expr = self.build(expr)
+ subs = self.build(subs)
+ return expr[subs]
+
+ def build_CallFunc(self, o):
+ children = map(self.build, o.getChildren())
+ callee = children.pop(0)
+ kwargs = children.pop() or {}
+ starargs = children.pop() or ()
+ args = tuple(children) + tuple(starargs)
+ return callee(*args, **kwargs)
+
+ def build_List(self, o):
+ return map(self.build, o.getChildren())
+
+ def build_Const(self, o):
+ return o.value
+
+ def build_Dict(self, o):
+ d = {}
+ i = iter(map(self.build, o.getChildren()))
+ for el in i:
+ d[el] = i.next()
+ return d
+
+ def build_Tuple(self, o):
+ return tuple(self.build_List(o))
+
+ def build_Name(self, o):
+ name = o.name
+ if name == 'None':
+ return None
+ if name == 'True':
+ return True
+ if name == 'False':
+ return False
+
+ # See if the Name is a package or module. If it is, import it.
+ try:
+ return modules(name)
+ except ImportError:
+ pass
+
+ # See if the Name is in builtins.
+ try:
+ import __builtin__
+ return getattr(__builtin__, name)
+ except AttributeError:
+ pass
+
+ raise TypeError("unrepr could not resolve the name %s" % repr(name))
+
+ def build_Add(self, o):
+ left, right = map(self.build, o.getChildren())
+ return left + right
+
+ def build_Getattr(self, o):
+ parent = self.build(o.expr)
+ return getattr(parent, o.attrname)
+
+ def build_NoneType(self, o):
+ return None
+
+ def build_UnarySub(self, o):
+ return -self.build(o.getChildren()[0])
+
+ def build_UnaryAdd(self, o):
+ return self.build(o.getChildren()[0])
+
+
+def _astnode(s):
+ """Return a Python ast Node compiled from a string."""
+ try:
+ import compiler
+ except ImportError:
+ # Fallback to eval when compiler package is not available,
+ # e.g. IronPython 1.0.
+ return eval(s)
+
+ p = compiler.parse("__tempvalue__ = " + s)
+ return p.getChildren()[1].getChildren()[0].getChildren()[1]
+
+
+def unrepr(s):
+ """Return a Python object compiled from a string."""
+ if not s:
+ return s
+ obj = _astnode(s)
+ return _Builder().build(obj)
+
+
+def modules(modulePath):
+ """Load a module and retrieve a reference to that module."""
+ try:
+ mod = sys.modules[modulePath]
+ if mod is None:
+ raise KeyError()
+ except KeyError:
+ # The last [''] is important.
+ mod = __import__(modulePath, globals(), locals(), [''])
+ return mod
+
+def attributes(full_attribute_name):
+ """Load a module and retrieve an attribute of that module."""
+
+ # Parse out the path, module, and attribute
+ last_dot = full_attribute_name.rfind(".")
+ attr_name = full_attribute_name[last_dot + 1:]
+ mod_path = full_attribute_name[:last_dot]
+
+ mod = modules(mod_path)
+ # Let an AttributeError propagate outward.
+ try:
+ attr = getattr(mod, attr_name)
+ except AttributeError:
+ raise AttributeError("'%s' object has no attribute '%s'"
+ % (mod_path, attr_name))
+
+ # Return a reference to the attribute.
+ return attr
+
+