|
|
"""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)
|
|
|
|