rewrite make_dict
This commit is contained in:
parent
ccac34b2db
commit
e9902d8ce2
|
@ -122,13 +122,13 @@ def test_make_dict():
|
||||||
BoolOption("a", "", default=False)]),
|
BoolOption("a", "", default=False)]),
|
||||||
IntOption("int", "", default=42)])
|
IntOption("int", "", default=42)])
|
||||||
config = Config(descr)
|
config = Config(descr)
|
||||||
d = make_dict(config)
|
d = config.make_dict()
|
||||||
assert d == {"s1.a": False, "int": 42}
|
assert d == {"s1.a": False, "int": 42}
|
||||||
config.int = 43
|
config.int = 43
|
||||||
config.s1.a = True
|
config.s1.a = True
|
||||||
d = make_dict(config)
|
d = config.make_dict()
|
||||||
assert d == {"s1.a": True, "int": 43}
|
assert d == {"s1.a": True, "int": 43}
|
||||||
d2 = make_dict(config, flatten=True)
|
d2 = config.make_dict(flatten=True)
|
||||||
assert d2 == {'a': True, 'int': 43}
|
assert d2 == {'a': True, 'int': 43}
|
||||||
|
|
||||||
#def test_delattr():
|
#def test_delattr():
|
||||||
|
|
|
@ -46,12 +46,12 @@ def test_base_config():
|
||||||
'general.mode_conteneur_actif': False, 'general.time_zone': 'Paris',
|
'general.mode_conteneur_actif': False, 'general.time_zone': 'Paris',
|
||||||
'interface1.ip_admin_eth0.netmask_admin_eth0': None, 'general.nom_machine':
|
'interface1.ip_admin_eth0.netmask_admin_eth0': None, 'general.nom_machine':
|
||||||
'eoleng', 'general.activer_proxy_client': False}
|
'eoleng', 'general.activer_proxy_client': False}
|
||||||
assert make_dict(config.creole) == result
|
assert config.creole.make_dict() == result
|
||||||
result = {'serveur_ntp': [], 'mode_conteneur_actif': False,
|
result = {'serveur_ntp': [], 'mode_conteneur_actif': False,
|
||||||
'ip_admin_eth0': None, 'time_zone': 'Paris', 'numero_etab': None,
|
'ip_admin_eth0': None, 'time_zone': 'Paris', 'numero_etab': None,
|
||||||
'netmask_admin_eth0': None, 'nom_machine': 'eoleng', 'activer_proxy_client':
|
'netmask_admin_eth0': None, 'nom_machine': 'eoleng', 'activer_proxy_client':
|
||||||
False, 'nombre_interfaces': 1}
|
False, 'nombre_interfaces': 1}
|
||||||
assert make_dict(config.creole, flatten=True) == result
|
assert config.creole.make_dict(flatten=True) == result
|
||||||
|
|
||||||
def test_get_group_type():
|
def test_get_group_type():
|
||||||
descr = make_description()
|
descr = make_description()
|
||||||
|
|
|
@ -124,7 +124,6 @@ class SubConfig(object):
|
||||||
rootconfig = self.cfgimpl_get_context()
|
rootconfig = self.cfgimpl_get_context()
|
||||||
path = rootconfig.cfgimpl_get_description().get_path_by_opt(opt_or_descr.opt)
|
path = rootconfig.cfgimpl_get_description().get_path_by_opt(opt_or_descr.opt)
|
||||||
return getattr(rootconfig, path)
|
return getattr(rootconfig, path)
|
||||||
|
|
||||||
self._validate(name, opt_or_descr, force_permissive=force_permissive)
|
self._validate(name, opt_or_descr, force_permissive=force_permissive)
|
||||||
if isinstance(opt_or_descr, OptionDescription):
|
if isinstance(opt_or_descr, OptionDescription):
|
||||||
children = self.cfgimpl_get_description()._children
|
children = self.cfgimpl_get_description()._children
|
||||||
|
@ -283,23 +282,100 @@ class SubConfig(object):
|
||||||
return context_descr.get_path_by_opt(descr)
|
return context_descr.get_path_by_opt(descr)
|
||||||
|
|
||||||
def get(self, name):
|
def get(self, name):
|
||||||
path = self.getpath()
|
"""
|
||||||
return self.cfgimpl_get_context().get(name, _subpath=path)
|
same as a `find_first()` method in a config that has identical names:
|
||||||
|
it returns the first item of an option named `name`
|
||||||
|
|
||||||
|
much like the attribute access way, except that
|
||||||
|
the search for the option is performed recursively in the whole
|
||||||
|
configuration tree.
|
||||||
|
|
||||||
|
:returns: option value.
|
||||||
|
"""
|
||||||
|
return self.cfgimpl_get_context()._find(byname=name, bytype=None,
|
||||||
|
byvalue=None, byattrs=None,
|
||||||
|
first=True, ret='value',
|
||||||
|
_subpath=self.getpath())
|
||||||
|
|
||||||
def find(self, bytype=None, byname=None, byvalue=None, byattrs=None):
|
def find(self, bytype=None, byname=None, byvalue=None, byattrs=None):
|
||||||
path = self.getpath()
|
"""
|
||||||
return self.cfgimpl_get_context().find(bytype=bytype, byname=byname,
|
finds a list of options recursively in the config
|
||||||
byvalue=byvalue,
|
|
||||||
byattrs=byattrs,
|
:param bytype: Option class (BoolOption, StrOption, ...)
|
||||||
_subpath=path)
|
:param byname: filter by Option._name
|
||||||
|
:param byvalue: filter by the option's value
|
||||||
|
:param byattrs: dict of option attributes (default, callback...)
|
||||||
|
:returns: list of matching Option objects
|
||||||
|
"""
|
||||||
|
return self.cfgimpl_get_context()._find(bytype, byname, byvalue,
|
||||||
|
byattrs, first=False,
|
||||||
|
_subpath=self.getpath())
|
||||||
|
|
||||||
def find_first(self, bytype=None, byname=None, byvalue=None, byattrs=None):
|
def find_first(self, bytype=None, byname=None, byvalue=None, byattrs=None):
|
||||||
path = self.getpath()
|
"""
|
||||||
return self.cfgimpl_get_context().find_first(bytype=bytype,
|
finds an option recursively in the config
|
||||||
byname=byname,
|
|
||||||
byvalue=byvalue,
|
:param bytype: Option class (BoolOption, StrOption, ...)
|
||||||
byattrs=byattrs,
|
:param byname: filter by Option._name
|
||||||
_subpath=path)
|
:param byvalue: filter by the option's value
|
||||||
|
:param byattrs: dict of option attributes (default, callback...)
|
||||||
|
:returns: list of matching Option objects
|
||||||
|
"""
|
||||||
|
return self.cfgimpl_get_context()._find(bytype, byname, byvalue,
|
||||||
|
byattrs, first=True,
|
||||||
|
_subpath=self.getpath())
|
||||||
|
|
||||||
|
def make_dict(self, flatten=False, _currpath=None, withoption=None, withvalue=None):
|
||||||
|
"""export the whole config into a `dict`
|
||||||
|
:returns: dict of Option's name (or path) and values"""
|
||||||
|
pathsvalues = []
|
||||||
|
if _currpath is None:
|
||||||
|
_currpath = []
|
||||||
|
if withoption is None and withvalue is not None:
|
||||||
|
raise ValueError("make_dict can't filtering with value without option")
|
||||||
|
if withoption is not None:
|
||||||
|
mypath = self.getpath()
|
||||||
|
for path in self.cfgimpl_get_context()._find(bytype=Option, byname=withoption,
|
||||||
|
byvalue=withvalue, byattrs=None,
|
||||||
|
first=False, ret='path', _subpath=mypath):
|
||||||
|
path = '.'.join(path.split('.')[:-1])
|
||||||
|
opt = self.cfgimpl_get_context().cfgimpl_get_description().get_opt_by_path(path)
|
||||||
|
if mypath is not None:
|
||||||
|
if mypath == path:
|
||||||
|
withoption = None
|
||||||
|
withvalue = None
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
tmypath = mypath + '.'
|
||||||
|
if not path.startswith(tmypath):
|
||||||
|
raise Exception('unexpected path {}, '
|
||||||
|
'should start with {}'.format(path, mypath))
|
||||||
|
path = path[len(tmypath):]
|
||||||
|
self._make_sub_dict(opt, path, pathsvalues, _currpath, flatten)
|
||||||
|
#withoption can be set to None below !
|
||||||
|
if withoption is None:
|
||||||
|
for opt in self.cfgimpl_get_description().getchildren():
|
||||||
|
path = opt._name
|
||||||
|
self._make_sub_dict(opt, path, pathsvalues, _currpath, flatten)
|
||||||
|
if _currpath == []:
|
||||||
|
options = dict(pathsvalues)
|
||||||
|
return options
|
||||||
|
return pathsvalues
|
||||||
|
|
||||||
|
def _make_sub_dict(self, opt, path, pathsvalues, _currpath, flatten):
|
||||||
|
if isinstance(opt, OptionDescription):
|
||||||
|
pathsvalues += getattr(self, path).make_dict(flatten,
|
||||||
|
_currpath + path.split('.'))
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
value = self._getattr(opt._name)
|
||||||
|
if flatten:
|
||||||
|
name = opt._name
|
||||||
|
else:
|
||||||
|
name = '.'.join(_currpath + [opt._name])
|
||||||
|
pathsvalues.append((name, value))
|
||||||
|
except PropertiesOptionError:
|
||||||
|
pass # this just a hidden or disabled option
|
||||||
|
|
||||||
|
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
@ -376,21 +452,10 @@ class Config(SubConfig):
|
||||||
'there is no option that matches %s'
|
'there is no option that matches %s'
|
||||||
' or the option is hidden or disabled' % (key, ))
|
' or the option is hidden or disabled' % (key, ))
|
||||||
|
|
||||||
def get(self, name, _subpath=None):
|
def getpath(self):
|
||||||
"""
|
return None
|
||||||
same as a `find_first()` method in a config that has identical names:
|
|
||||||
it returns the first item of an option named `name`
|
|
||||||
|
|
||||||
much like the attribute access way, except that
|
def _find(self, bytype, byname, byvalue, byattrs, first, ret='option',
|
||||||
the search for the option is performed recursively in the whole
|
|
||||||
configuration tree.
|
|
||||||
|
|
||||||
:returns: option value.
|
|
||||||
"""
|
|
||||||
return self._find(byname=name, bytype=None, byvalue=None, byattrs=None,
|
|
||||||
first=True, getvalue=True, _subpath=_subpath)
|
|
||||||
|
|
||||||
def _find(self, bytype, byname, byvalue, byattrs, first, getvalue=False,
|
|
||||||
_subpath=None):
|
_subpath=None):
|
||||||
"""
|
"""
|
||||||
convenience method for finding an option that lives only in the subtree
|
convenience method for finding an option that lives only in the subtree
|
||||||
|
@ -436,14 +501,15 @@ class Config(SubConfig):
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
return True
|
return True
|
||||||
|
if ret not in ('option', 'path', 'value'):
|
||||||
|
raise ValueError('unknown ret type {} for _find'.format(ret))
|
||||||
find_results = []
|
find_results = []
|
||||||
opts, paths = self.cfgimpl_get_description()._cache_paths
|
opts, paths = self.cfgimpl_get_description()._cache_paths
|
||||||
for index in range(0, len(paths)):
|
for index in range(0, len(paths)):
|
||||||
path = paths[index]
|
|
||||||
option = opts[index]
|
option = opts[index]
|
||||||
if isinstance(option, OptionDescription):
|
if isinstance(option, OptionDescription):
|
||||||
continue
|
continue
|
||||||
|
path = paths[index]
|
||||||
if _subpath is not None and not path.startswith(_subpath + '.'):
|
if _subpath is not None and not path.startswith(_subpath + '.'):
|
||||||
continue
|
continue
|
||||||
if not _filter_by_name():
|
if not _filter_by_name():
|
||||||
|
@ -459,64 +525,21 @@ class Config(SubConfig):
|
||||||
value = getattr(self, path)
|
value = getattr(self, path)
|
||||||
except: # a property restricts the access of the value
|
except: # a property restricts the access of the value
|
||||||
continue
|
continue
|
||||||
|
if ret == 'value':
|
||||||
|
retval = value
|
||||||
|
elif ret == 'path':
|
||||||
|
retval = path
|
||||||
|
else:
|
||||||
|
retval = option
|
||||||
if first:
|
if first:
|
||||||
if getvalue:
|
return retval
|
||||||
return value
|
|
||||||
else:
|
else:
|
||||||
return option
|
find_results.append(retval)
|
||||||
else:
|
|
||||||
if getvalue:
|
|
||||||
find_results.append(value)
|
|
||||||
else:
|
|
||||||
find_results.append(option)
|
|
||||||
if find_results == []:
|
if find_results == []:
|
||||||
raise NotFoundError("no option found in config with these criteria")
|
raise NotFoundError("no option found in config with these criteria")
|
||||||
else:
|
else:
|
||||||
return find_results
|
return find_results
|
||||||
|
|
||||||
def find(self, bytype=None, byname=None, byvalue=None, byattrs=None, _subpath=None):
|
|
||||||
"""
|
|
||||||
finds a list of options recursively in the config
|
|
||||||
|
|
||||||
:param bytype: Option class (BoolOption, StrOption, ...)
|
|
||||||
:param byname: filter by Option._name
|
|
||||||
:param byvalue: filter by the option's value
|
|
||||||
:param byattrs: dict of option attributes (default, callback...)
|
|
||||||
:returns: list of matching Option objects
|
|
||||||
"""
|
|
||||||
return self._find(bytype, byname, byvalue, byattrs, first=False, _subpath=_subpath)
|
|
||||||
|
|
||||||
def find_first(self, bytype=None, byname=None, byvalue=None, byattrs=None, _subpath=None):
|
|
||||||
"""
|
|
||||||
finds an option recursively in the config
|
|
||||||
|
|
||||||
:param bytype: Option class (BoolOption, StrOption, ...)
|
|
||||||
:param byname: filter by Option._name
|
|
||||||
:param byvalue: filter by the option's value
|
|
||||||
:param byattrs: dict of option attributes (default, callback...)
|
|
||||||
:returns: list of matching Option objects
|
|
||||||
"""
|
|
||||||
return self._find(bytype, byname, byvalue, byattrs, first=True, _subpath=_subpath)
|
|
||||||
|
|
||||||
|
|
||||||
def make_dict(config, flatten=False):
|
|
||||||
"""export the whole config into a `dict`
|
|
||||||
:returns: dict of Option's name (or path) and values"""
|
|
||||||
paths = config.getpaths()
|
|
||||||
pathsvalues = []
|
|
||||||
for path in paths:
|
|
||||||
if flatten:
|
|
||||||
pathname = path.split('.')[-1]
|
|
||||||
else:
|
|
||||||
pathname = path
|
|
||||||
try:
|
|
||||||
value = getattr(config, path)
|
|
||||||
pathsvalues.append((pathname, value))
|
|
||||||
except:
|
|
||||||
pass # this just a hidden or disabled option
|
|
||||||
options = dict(pathsvalues)
|
|
||||||
return options
|
|
||||||
|
|
||||||
|
|
||||||
def mandatory_warnings(config):
|
def mandatory_warnings(config):
|
||||||
"""convenience function to trace Options that are mandatory and
|
"""convenience function to trace Options that are mandatory and
|
||||||
|
|
|
@ -408,12 +408,9 @@ class OptionDescription(BaseInformation):
|
||||||
return self.get_information('doc')
|
return self.get_information('doc')
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
if name in self._children[0]:
|
|
||||||
return self._children[1][self._children[0].index(name)]
|
|
||||||
else:
|
|
||||||
try:
|
try:
|
||||||
object.__getattr__(self, name)
|
return self._children[1][self._children[0].index(name)]
|
||||||
except AttributeError:
|
except ValueError:
|
||||||
raise AttributeError('unknown Option {} in OptionDescription {}'
|
raise AttributeError('unknown Option {} in OptionDescription {}'
|
||||||
''.format(name, self._name))
|
''.format(name, self._name))
|
||||||
|
|
||||||
|
@ -421,50 +418,49 @@ class OptionDescription(BaseInformation):
|
||||||
return tuple([child.getkey(getattr(config, child._name))
|
return tuple([child.getkey(getattr(config, child._name))
|
||||||
for child in self._children[1]])
|
for child in self._children[1]])
|
||||||
|
|
||||||
def getpaths(self, include_groups=False, currpath=None):
|
def getpaths(self, include_groups=False, _currpath=None):
|
||||||
"""returns a list of all paths in self, recursively
|
"""returns a list of all paths in self, recursively
|
||||||
currpath should not be provided (helps with recursion)
|
_currpath should not be provided (helps with recursion)
|
||||||
"""
|
"""
|
||||||
#FIXME : cache
|
#FIXME : cache
|
||||||
if currpath is None:
|
if _currpath is None:
|
||||||
currpath = []
|
_currpath = []
|
||||||
paths = []
|
paths = []
|
||||||
for option in self._children[1]:
|
for option in self._children[1]:
|
||||||
attr = option._name
|
attr = option._name
|
||||||
if attr.startswith('_cfgimpl'):
|
|
||||||
continue
|
|
||||||
if isinstance(option, OptionDescription):
|
if isinstance(option, OptionDescription):
|
||||||
if include_groups:
|
if include_groups:
|
||||||
paths.append('.'.join(currpath + [attr]))
|
paths.append('.'.join(_currpath + [attr]))
|
||||||
currpath.append(attr)
|
|
||||||
paths += option.getpaths(include_groups=include_groups,
|
paths += option.getpaths(include_groups=include_groups,
|
||||||
currpath=currpath)
|
_currpath=_currpath + [attr])
|
||||||
currpath.pop()
|
|
||||||
else:
|
else:
|
||||||
paths.append('.'.join(currpath + [attr]))
|
paths.append('.'.join(_currpath + [attr]))
|
||||||
return paths
|
return paths
|
||||||
|
|
||||||
def build_cache(self, cache_path=None, cache_option=None, currpath=None):
|
def getchildren(self):
|
||||||
if currpath is None and self._cache_paths is not None:
|
return self._children[1]
|
||||||
|
|
||||||
|
def build_cache(self, cache_path=None, cache_option=None, _currpath=None):
|
||||||
|
if _currpath is None and self._cache_paths is not None:
|
||||||
return
|
return
|
||||||
if currpath is None:
|
if _currpath is None:
|
||||||
save = True
|
save = True
|
||||||
currpath = []
|
_currpath = []
|
||||||
else:
|
else:
|
||||||
save = False
|
save = False
|
||||||
if cache_path is None:
|
if cache_path is None:
|
||||||
cache_path = []
|
cache_path = [self._name]
|
||||||
cache_option = []
|
cache_option = [self]
|
||||||
for option in self._children[1]:
|
for option in self._children[1]:
|
||||||
attr = option._name
|
attr = option._name
|
||||||
if attr.startswith('_cfgimpl'):
|
if attr.startswith('_cfgimpl'):
|
||||||
continue
|
continue
|
||||||
cache_option.append(option)
|
cache_option.append(option)
|
||||||
cache_path.append(str('.'.join(currpath + [attr])))
|
cache_path.append(str('.'.join(_currpath + [attr])))
|
||||||
if isinstance(option, OptionDescription):
|
if isinstance(option, OptionDescription):
|
||||||
currpath.append(attr)
|
_currpath.append(attr)
|
||||||
option.build_cache(cache_path, cache_option, currpath)
|
option.build_cache(cache_path, cache_option, _currpath)
|
||||||
currpath.pop()
|
_currpath.pop()
|
||||||
if save:
|
if save:
|
||||||
#valid no duplicated option
|
#valid no duplicated option
|
||||||
valid_child = copy(cache_option)
|
valid_child = copy(cache_option)
|
||||||
|
|
|
@ -123,13 +123,13 @@ class Values(object):
|
||||||
def _getitem(self, opt, force_properties=None):
|
def _getitem(self, opt, force_properties=None):
|
||||||
# options with callbacks
|
# options with callbacks
|
||||||
value = self._get_value(opt)
|
value = self._get_value(opt)
|
||||||
if opt.has_callback():
|
|
||||||
setting = self.context.cfgimpl_get_settings()
|
setting = self.context.cfgimpl_get_settings()
|
||||||
if (not setting.has_property('frozen', opt) or
|
if opt.has_callback():
|
||||||
(setting.has_property('frozen', opt) and
|
is_frozen = setting.has_property('frozen', opt)
|
||||||
|
if (not is_frozen or (is_frozen and
|
||||||
not setting.has_property('force_default_on_freeze', opt)
|
not setting.has_property('force_default_on_freeze', opt)
|
||||||
)) and not self.context.cfgimpl_get_values().is_default_owner(opt):
|
)) and not self.context.cfgimpl_get_values().is_default_owner(opt):
|
||||||
return self._get_value(opt)
|
return value
|
||||||
try:
|
try:
|
||||||
result = opt.getcallback_value(self.context)
|
result = opt.getcallback_value(self.context)
|
||||||
except NoValueReturned:
|
except NoValueReturned:
|
||||||
|
@ -149,7 +149,7 @@ class Values(object):
|
||||||
raise ConfigError('invalid calculated value returned'
|
raise ConfigError('invalid calculated value returned'
|
||||||
' for option {0}'.format(opt._name))
|
' for option {0}'.format(opt._name))
|
||||||
# frozen and force default
|
# frozen and force default
|
||||||
if not opt.has_callback() and self.context.cfgimpl_get_settings().has_property('force_default_on_freeze', opt):
|
elif setting.has_property('force_default_on_freeze', opt):
|
||||||
value = opt.getdefault()
|
value = opt.getdefault()
|
||||||
if opt.is_multi():
|
if opt.is_multi():
|
||||||
value = self.fill_multi(opt, value)
|
value = self.fill_multi(opt, value)
|
||||||
|
|
Loading…
Reference in New Issue