##// END OF EJS Templates
Merge sconfig branch.
Merge sconfig branch.

File last commit:

r1253:9ce3a358
r1253:9ce3a358
Show More
config.py
179 lines | 4.7 KiB | text/x-python | PythonLexer
"""Load and store configuration objects.
Test this module using
nosetests -v --with-doctest --doctest-tests IPython.config
"""
from __future__ import with_statement
from contextlib import contextmanager
import inspect
import types
from IPython.config import traitlets
from traitlets import Traitlet
from IPython.external.configobj import ConfigObj
def debug(s):
import sys
sys.stderr.write(str(s) + '\n')
@contextmanager
def raw(config):
"""Context manager for accessing traitlets directly.
"""
config.__getattribute__('',raw_access=True)
yield config
config.__getattribute__('',raw_access=False)
class Config(object):
"""
Implementation Notes
====================
All instances of the same Config class share properties. Therefore,
>>> class Sample(Config):
... my_float = traitlets.Float(3)
>>> s0 = Sample()
>>> s1 = Sample()
>>> s0.my_float = 5
>>> s0.my_float == s1.my_float
True
"""
def __init__(self):
# Instantiate subconfigs
with raw(self):
subconfigs = [(n,v) for n,v in
inspect.getmembers(self, inspect.isclass)
if not n.startswith('__')]
for n,v in subconfigs:
setattr(self, n, v())
def __getattribute__(self,attr,raw_access=None,
_ns={'raw_access':False}):
if raw_access is not None:
_ns['raw_access'] = raw_access
return
obj = object.__getattribute__(self,attr)
if isinstance(obj,Traitlet) and not _ns['raw_access']:
return obj.__call__()
else:
return obj
def __setattr__(self,attr,value):
obj = object.__getattribute__(self,attr)
if isinstance(obj,Traitlet):
obj(value)
else:
self.__dict__[attr] = value
def __str__(self,level=1,only_modified=True):
ci = ConfigInspector(self)
out = ''
spacer = ' '*(level-1)
# Add traitlet representations
for p,v in ci.properties:
if (v.modified and only_modified) or not only_modified:
out += spacer + '%s = %s\n' % (p,v)
# Add subconfig representations
for (n,v) in ci.subconfigs:
sub_str = v.__str__(level=level+1,only_modified=only_modified)
if sub_str:
out += '\n' + spacer + '[' * level + ('%s' % n) \
+ ']'*level + '\n'
out += sub_str
return out
def __iadd__(self,source):
"""Load configuration from filename, and update self.
"""
if not isinstance(source,dict):
source = ConfigObj(source, unrepr=True)
update_from_dict(self,source)
return self
class ConfigInspector(object):
"""Allow the inspection of Config objects.
"""
def __init__(self,config):
self._config = config
@property
def properties(self):
"Return all traitlet names."
with raw(self._config):
return inspect.getmembers(self._config,
lambda obj: isinstance(obj, Traitlet))
@property
def subconfigs(self):
"Return all subconfig names and values."
with raw(self._config):
return [(n,v) for n,v in
inspect.getmembers(self._config,
lambda obj: isinstance(obj,Config))
if not n.startswith('__')]
def reset(self):
for (p,v) in self.properties:
v.reset()
for (s,v) in self.subconfigs:
ConfigInspector(v).reset()
def update_from_dict(config,d):
"""Propagate the values of the dictionary to the given configuration.
Useful to load configobj instances.
"""
for k,v in d.items():
try:
prop_or_subconfig = getattr(config, k)
except AttributeError:
print "Invalid section/property in config file: %s" % k
else:
if isinstance(v,dict):
update_from_dict(prop_or_subconfig,v)
else:
setattr(config, k, v)
def dict_from_config(config,only_modified=True):
"""Create a dictionary from a Config object."""
ci = ConfigInspector(config)
out = {}
for p,v in ci.properties:
if (v.modified and only_modified) or not only_modified:
out[p] = v
for s,v in ci.subconfigs:
d = dict_from_config(v,only_modified)
if d != {}:
out[s] = d
return out
def write(config, target):
"""Write a configuration to file.
"""
if isinstance(target, str):
target = open(target, 'w+')
target.flush()
target.seek(0)
confobj = ConfigObj(dict_from_config(config), unrepr=True)
confobj.write(target)