reorganize
This commit is contained in:
parent
30cd543a21
commit
6805cecfd5
50 changed files with 2517 additions and 1979 deletions
|
@ -1179,7 +1179,11 @@ def autocheck_permissive(cfg, mcfg, pathread, pathwrite, confread, confwrite, **
|
||||||
cfg2_ = cfg.config(confread).unrestraint
|
cfg2_ = cfg.config(confread).unrestraint
|
||||||
else:
|
else:
|
||||||
cfg2_ = cfg.unrestraint
|
cfg2_ = cfg.unrestraint
|
||||||
assert cfg_.option(pathread).permissive.get() == frozenset()
|
|
||||||
|
if not cfg_.option(pathread).option.isfollower():
|
||||||
|
assert cfg_.option(pathread).permissive.get() == frozenset()
|
||||||
|
else:
|
||||||
|
assert cfg_.option(pathread, 0).permissive.get() == frozenset()
|
||||||
if kwargs.get('permissive_od', False):
|
if kwargs.get('permissive_od', False):
|
||||||
assert cfg_.option(pathread.rsplit('.', 1)[0]).permissive.get() == frozenset()
|
assert cfg_.option(pathread.rsplit('.', 1)[0]).permissive.get() == frozenset()
|
||||||
|
|
||||||
|
@ -1200,7 +1204,10 @@ def autocheck_permissive(cfg, mcfg, pathread, pathwrite, confread, confwrite, **
|
||||||
cfg_.option(call_path).permissive.set(frozenset(['disabled']))
|
cfg_.option(call_path).permissive.set(frozenset(['disabled']))
|
||||||
|
|
||||||
# have permissive?
|
# have permissive?
|
||||||
assert cfg_.option(pathread).permissive.get() == frozenset(['disabled'])
|
if not cfg_.option(pathread).option.isfollower():
|
||||||
|
assert cfg_.option(pathread).permissive.get() == frozenset(['disabled'])
|
||||||
|
else:
|
||||||
|
assert cfg_.option(pathread, 0).permissive.get() == frozenset(['disabled'])
|
||||||
#if confwrite != confread:
|
#if confwrite != confread:
|
||||||
# assert cfg.config(confread).unrestraint.option(pathread).permissive.get() == frozenset(['disabled'])
|
# assert cfg.config(confread).unrestraint.option(pathread).permissive.get() == frozenset(['disabled'])
|
||||||
|
|
||||||
|
|
|
@ -152,6 +152,16 @@ def test_information_config():
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def test_information_config_list():
|
||||||
|
od1 = make_description()
|
||||||
|
cfg = Config(od1)
|
||||||
|
string = 'some informations'
|
||||||
|
cfg.information.set('info', string)
|
||||||
|
#
|
||||||
|
assert cfg.information.exportation() == {None: {'info': string}}
|
||||||
|
assert set(cfg.information.list()) == {'info', 'doc'}
|
||||||
|
|
||||||
|
|
||||||
def test_information_exportation():
|
def test_information_exportation():
|
||||||
od1 = make_description()
|
od1 = make_description()
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
|
@ -199,6 +209,18 @@ def test_information_option():
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def test_information_option_2():
|
||||||
|
i1 = IntOption('test1', '')
|
||||||
|
i1.impl_set_information('info', 'value')
|
||||||
|
# it's a dict
|
||||||
|
assert set(i1.impl_list_information()) == {'info', 'doc'}
|
||||||
|
od1 = OptionDescription('test', '', [i1])
|
||||||
|
cfg = Config(od1)
|
||||||
|
# it's tuples
|
||||||
|
assert set(cfg.option('test1').information.list()) == {'info', 'doc'}
|
||||||
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
def test_information_optiondescription():
|
def test_information_optiondescription():
|
||||||
od1 = make_description()
|
od1 = make_description()
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
|
@ -390,8 +412,7 @@ def test_config_od_name(config_type):
|
||||||
cfg = get_config(cfg, config_type)
|
cfg = get_config(cfg, config_type)
|
||||||
assert cfg.option('val.i').option.name() == 'i'
|
assert cfg.option('val.i').option.name() == 'i'
|
||||||
assert cfg.option('val.s').option.name() == 's'
|
assert cfg.option('val.s').option.name() == 's'
|
||||||
assert cfg.option('val.s').option.name(follow_symlink=True) == 'i'
|
assert cfg.option('val.s').option.type() == _('integer')
|
||||||
assert cfg.option('val.s').option.type() == 'integer'
|
|
||||||
assert cfg.option('val').option.type() == 'optiondescription'
|
assert cfg.option('val').option.type() == 'optiondescription'
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
@ -403,7 +424,7 @@ def test_config_od_type(config_type):
|
||||||
cfg = Config(o2)
|
cfg = Config(o2)
|
||||||
cfg = get_config(cfg, config_type)
|
cfg = get_config(cfg, config_type)
|
||||||
assert cfg.option('val').option.type() == 'optiondescription'
|
assert cfg.option('val').option.type() == 'optiondescription'
|
||||||
assert cfg.option('val.i').option.type() == 'integer'
|
assert cfg.option('val.i').option.type() == _('integer')
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1649,7 +1649,6 @@ def test_invalid_subdynod_dyndescription():
|
||||||
def test_invalid_symlink_dyndescription():
|
def test_invalid_symlink_dyndescription():
|
||||||
st = StrOption('st', '')
|
st = StrOption('st', '')
|
||||||
st2 = SymLinkOption('st2', st)
|
st2 = SymLinkOption('st2', st)
|
||||||
st2
|
|
||||||
with pytest.raises(ConfigError):
|
with pytest.raises(ConfigError):
|
||||||
DynOptionDescription('dod', '', [st, st2], suffixes=Calculation(return_list))
|
DynOptionDescription('dod', '', [st, st2], suffixes=Calculation(return_list))
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
@ -1658,7 +1657,6 @@ def test_invalid_symlink_dyndescription():
|
||||||
def test_nocallback_dyndescription():
|
def test_nocallback_dyndescription():
|
||||||
st = StrOption('st', '')
|
st = StrOption('st', '')
|
||||||
st2 = StrOption('st2', '')
|
st2 = StrOption('st2', '')
|
||||||
st, st2
|
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
DynOptionDescription('dod', '', [st, st2])
|
DynOptionDescription('dod', '', [st, st2])
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
@ -1843,10 +1841,9 @@ def test_dyn_leadership_requires():
|
||||||
def test_dyn_leadership_mandatory():
|
def test_dyn_leadership_mandatory():
|
||||||
nsd_zones_all = StrOption(name="nsd_zones_all", doc="nsd_zones_all", multi=True, default=['val1', 'val2'])
|
nsd_zones_all = StrOption(name="nsd_zones_all", doc="nsd_zones_all", multi=True, default=['val1', 'val2'])
|
||||||
is_auto = BoolOption(name="is_auto_", doc="is auto")
|
is_auto = BoolOption(name="is_auto_", doc="is auto")
|
||||||
# hostname = DomainnameOption(name="hostname_", multi=True, type='hostname', properties=frozenset({Calculation(func.calc_value, Params(ParamValue('frozen'), kwargs={'condition': ParamOption(is_auto, todict=True, notraisepropertyerror=True), 'expected': ParamValue(True)})), Calculation(func.calc_value, Params(ParamValue('force_default_on_freeze'), kwargs={'condition': ParamOption(is_auto, todict=True, notraisepropertyerror=True), 'expected': ParamValue(True)}))}))
|
|
||||||
hostname = DomainnameOption(name="hostname_", doc="hostname_", multi=True, type='hostname')
|
hostname = DomainnameOption(name="hostname_", doc="hostname_", multi=True, type='hostname')
|
||||||
choice = ChoiceOption(name="type_", doc="type_", values=('A', 'CNAME'), multi=True, default_multi="A")
|
choice = ChoiceOption(name="type_", doc="type_", values=('A', 'CNAME'), multi=True, default_multi="A")
|
||||||
leadership = Leadership(name="hostname_", doc="hostname_", children=[hostname, choice], properties=frozenset({Calculation(calc_value, Params(ParamValue('hidden'), kwargs={'condition': ParamOption(is_auto, todict=True, notraisepropertyerror=True), 'expected': ParamValue(True)}))}))
|
leadership = Leadership(name="hostname_", doc="hostname_", children=[hostname, choice], properties=frozenset({Calculation(calc_value, Params(ParamValue('hidden'), kwargs={'condition': ParamOption(is_auto, notraisepropertyerror=True), 'expected': ParamValue(True)}))}))
|
||||||
dyn = DynOptionDescription(name="nsd_zone_", doc="Zone ", suffixes=Calculation(calc_value, Params((ParamOption(nsd_zones_all, notraisepropertyerror=True)))), children=[is_auto, leadership], properties=frozenset({"normal"}))
|
dyn = DynOptionDescription(name="nsd_zone_", doc="Zone ", suffixes=Calculation(calc_value, Params((ParamOption(nsd_zones_all, notraisepropertyerror=True)))), children=[is_auto, leadership], properties=frozenset({"normal"}))
|
||||||
od1 = OptionDescription(name="nsd", doc="nsd", children=[nsd_zones_all, dyn])
|
od1 = OptionDescription(name="nsd", doc="nsd", children=[nsd_zones_all, dyn])
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
|
|
|
@ -6,11 +6,11 @@ import pytest
|
||||||
|
|
||||||
from tiramisu.setting import groups, owners
|
from tiramisu.setting import groups, owners
|
||||||
from tiramisu import ChoiceOption, BoolOption, IntOption, IPOption, NetworkOption, NetmaskOption, \
|
from tiramisu import ChoiceOption, BoolOption, IntOption, IPOption, NetworkOption, NetmaskOption, \
|
||||||
StrOption, OptionDescription, Leadership, Config
|
StrOption, OptionDescription, Leadership, Config, Calculation, ParamValue, calc_value, Params
|
||||||
from tiramisu.error import LeadershipError, PropertiesOptionError, ConfigError
|
from tiramisu.error import LeadershipError, PropertiesOptionError, ConfigError
|
||||||
|
|
||||||
|
|
||||||
groups.family = groups.GroupType('family')
|
groups.addgroup('family')
|
||||||
|
|
||||||
|
|
||||||
def compare(calculated, expected):
|
def compare(calculated, expected):
|
||||||
|
@ -94,10 +94,12 @@ def test_iter_on_groups():
|
||||||
#test StopIteration
|
#test StopIteration
|
||||||
break
|
break
|
||||||
result = cfg.option('creole').list('option',
|
result = cfg.option('creole').list('option',
|
||||||
group_type=groups.family)
|
group_type=groups.family,
|
||||||
|
)
|
||||||
assert list(result) == []
|
assert list(result) == []
|
||||||
result = cfg.option('creole.general').list('optiondescription',
|
result = cfg.option('creole.general').list('optiondescription',
|
||||||
group_type=groups.family)
|
group_type=groups.family,
|
||||||
|
)
|
||||||
assert list(result) == []
|
assert list(result) == []
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
@ -218,6 +220,61 @@ def test_groups_is_leader(config_type):
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def test_leader_list(config_type):
|
||||||
|
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||||
|
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True, default_multi='value')
|
||||||
|
interface1 = Leadership('leadership', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||||
|
od1 = OptionDescription('od', '', [interface1])
|
||||||
|
cfg = Config(od1)
|
||||||
|
cfg = get_config(cfg, config_type)
|
||||||
|
ret = cfg.option.list('all')
|
||||||
|
assert len(ret) == 1
|
||||||
|
assert ret[0].option.name() == 'leadership'
|
||||||
|
#
|
||||||
|
ret = cfg.option('leadership').list('all')
|
||||||
|
assert len(ret) == 1
|
||||||
|
assert ret[0].option.name() == 'ip_admin_eth0'
|
||||||
|
#
|
||||||
|
cfg.option('leadership.ip_admin_eth0').value.set(['a', 'b'])
|
||||||
|
cfg.option('leadership.netmask_admin_eth0', 0).value.set('c')
|
||||||
|
cfg.option('leadership.netmask_admin_eth0', 1).value.set('d')
|
||||||
|
ret = cfg.option('leadership').list('all')
|
||||||
|
assert ret[0].option.name() == 'ip_admin_eth0'
|
||||||
|
assert ret[1].option.name() == 'netmask_admin_eth0'
|
||||||
|
# assert ret[1].option.index() == 0
|
||||||
|
# assert ret[2].option.name() == 'netmask_admin_eth0'
|
||||||
|
# assert ret[2].option.index() == 1
|
||||||
|
# assert len(ret) == 3
|
||||||
|
# if config_type == 'tiramisu-api':
|
||||||
|
# cfg.send()
|
||||||
|
## assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def test_groups_is_multi_with_index(config_type):
|
||||||
|
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", ['val'], multi=True)
|
||||||
|
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True, default_multi='value')
|
||||||
|
interface1 = Leadership('leadership', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||||
|
var = StrOption('var', "ip réseau autorisé", multi=True)
|
||||||
|
od2 = OptionDescription('od2', '', [var])
|
||||||
|
od1 = OptionDescription('od', '', [interface1, od2])
|
||||||
|
cfg = Config(od1)
|
||||||
|
cfg = get_config(cfg, config_type)
|
||||||
|
assert cfg.option('leadership.netmask_admin_eth0', 0).option.ismulti()
|
||||||
|
|
||||||
|
|
||||||
|
def test_groups_is_information_with_index(config_type):
|
||||||
|
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", ['val'], multi=True)
|
||||||
|
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True, default_multi='value')
|
||||||
|
interface1 = Leadership('leadership', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||||
|
var = StrOption('var', "ip réseau autorisé", multi=True)
|
||||||
|
od2 = OptionDescription('od2', '', [var])
|
||||||
|
od1 = OptionDescription('od', '', [interface1, od2])
|
||||||
|
cfg = Config(od1)
|
||||||
|
cfg = get_config(cfg, config_type)
|
||||||
|
with pytest.raises(ConfigError):
|
||||||
|
assert cfg.option('leadership.netmask_admin_eth0', 0).information.set('key', 'value')
|
||||||
|
|
||||||
|
|
||||||
def test_groups_with_leader_in_root():
|
def test_groups_with_leader_in_root():
|
||||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
|
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
|
||||||
|
@ -436,6 +493,9 @@ def test_groups_with_leader_index_mandatory(config_type):
|
||||||
cfg.property.read_write()
|
cfg.property.read_write()
|
||||||
cfg = get_config(cfg, config_type)
|
cfg = get_config(cfg, config_type)
|
||||||
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.1'])
|
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.1'])
|
||||||
|
# index not allowed for leader
|
||||||
|
with pytest.raises(ConfigError):
|
||||||
|
cfg.option('ip_admin_eth0.ip_admin_eth0', 0).value.get()
|
||||||
# index is mandatory
|
# index is mandatory
|
||||||
with pytest.raises(ConfigError):
|
with pytest.raises(ConfigError):
|
||||||
cfg.option('ip_admin_eth0.netmask_admin_eth0').value.reset()
|
cfg.option('ip_admin_eth0.netmask_admin_eth0').value.reset()
|
||||||
|
@ -907,7 +967,7 @@ def test_wrong_index():
|
||||||
assert cfg.option('od.ip_admin_eth0.ip_admin_eth0').option.get()
|
assert cfg.option('od.ip_admin_eth0.ip_admin_eth0').option.get()
|
||||||
with pytest.raises(ConfigError):
|
with pytest.raises(ConfigError):
|
||||||
cfg.option('od.ip_admin_eth0.ip_admin_eth0', 0).option.get()
|
cfg.option('od.ip_admin_eth0.ip_admin_eth0', 0).option.get()
|
||||||
assert cfg.option('od.ip_admin_eth0.netmask_admin_eth0', 0).option.get()
|
assert cfg.option('od.ip_admin_eth0.netmask_admin_eth0').option.get()
|
||||||
assert cfg.option('od.ip_admin_eth0').option.get()
|
assert cfg.option('od.ip_admin_eth0').option.get()
|
||||||
with pytest.raises(ConfigError):
|
with pytest.raises(ConfigError):
|
||||||
cfg.option('od.ip_admin_eth0', 0).option.get()
|
cfg.option('od.ip_admin_eth0', 0).option.get()
|
||||||
|
@ -1011,17 +1071,14 @@ def test_follower_properties():
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
cfg.property.read_write()
|
cfg.property.read_write()
|
||||||
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['1.1.1.1', '192.168.0.0'])
|
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['1.1.1.1', '192.168.0.0'])
|
||||||
cfg.option('ip_admin_eth0.netmask_admin_eth0').property.get() == ('aproperty',)
|
|
||||||
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).property.get() == ('aproperty',)
|
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).property.get() == ('aproperty',)
|
||||||
cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).property.get() == ('aproperty',)
|
cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).property.get() == ('aproperty',)
|
||||||
#
|
#
|
||||||
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).property.add('newproperty')
|
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).property.add('newproperty')
|
||||||
cfg.option('ip_admin_eth0.netmask_admin_eth0').property.get() == ('aproperty',)
|
|
||||||
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).property.get() == ('aproperty', 'newproperty')
|
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).property.get() == ('aproperty', 'newproperty')
|
||||||
cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).property.get() == ('aproperty',)
|
cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).property.get() == ('aproperty',)
|
||||||
#
|
#
|
||||||
cfg.option('ip_admin_eth0.netmask_admin_eth0').property.add('newproperty1')
|
cfg.option('ip_admin_eth0.netmask_admin_eth0').property.add('newproperty1')
|
||||||
cfg.option('ip_admin_eth0.netmask_admin_eth0').property.get() == ('aproperty', 'newproperty1')
|
|
||||||
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).property.get() == ('aproperty', 'newproperty', 'newproperty1')
|
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).property.get() == ('aproperty', 'newproperty', 'newproperty1')
|
||||||
cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).property.get() == ('aproperty', 'newproperty1')
|
cfg.option('ip_admin_eth0.netmask_admin_eth0', 1).property.get() == ('aproperty', 'newproperty1')
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
@ -1036,3 +1093,24 @@ def test_api_get_leader(config_type):
|
||||||
option = cfg.option('ip_admin_eth0.netmask_admin_eth0').option.leader()
|
option = cfg.option('ip_admin_eth0.netmask_admin_eth0').option.leader()
|
||||||
assert option.option.get() == ip_admin_eth0
|
assert option.option.get() == ip_admin_eth0
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def test_leader_forbidden_properties(config_type):
|
||||||
|
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||||
|
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
|
||||||
|
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||||
|
od1 = OptionDescription('conf', '', [interface1])
|
||||||
|
cfg = Config(od1)
|
||||||
|
with pytest.raises(LeadershipError):
|
||||||
|
cfg.option('ip_admin_eth0.ip_admin_eth0').property.add('permissive')
|
||||||
|
|
||||||
|
|
||||||
|
def test_leader_forbidden_properties_callback(config_type):
|
||||||
|
calc_property = Calculation(calc_value, Params(ParamValue('permissive')))
|
||||||
|
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True, properties=(calc_property,))
|
||||||
|
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
|
||||||
|
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||||
|
od1 = OptionDescription('conf', '', [interface1])
|
||||||
|
cfg = Config(od1)
|
||||||
|
with pytest.raises(LeadershipError):
|
||||||
|
cfg.option('ip_admin_eth0.ip_admin_eth0').value.get()
|
||||||
|
|
|
@ -835,10 +835,10 @@ def test_meta_properties_requires1():
|
||||||
opt2 = BoolOption('opt2', "")
|
opt2 = BoolOption('opt2', "")
|
||||||
disabled_property = Calculation(calc_value,
|
disabled_property = Calculation(calc_value,
|
||||||
Params(ParamValue('disabled'),
|
Params(ParamValue('disabled'),
|
||||||
kwargs={'condition': ParamOption(opt1, todict=True),
|
kwargs={'condition': ParamOption(opt1),
|
||||||
'expected': ParamValue(False)}))
|
'expected': ParamValue(False)}))
|
||||||
od2 = OptionDescription('od2', "", [opt2], properties=(disabled_property,))
|
od2 = OptionDescription('od2', "", [opt2], properties=(disabled_property,))
|
||||||
opt3 = BoolOption('opt3', '', validators=[Calculation(valid_not_equal, Params((ParamOption(opt2), ParamSelfOption())))])
|
opt3 = BoolOption('opt3', '', validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(opt2))))])
|
||||||
od = OptionDescription('root', '', [opt1, od2, opt3])
|
od = OptionDescription('root', '', [opt1, od2, opt3])
|
||||||
conf1 = Config(od, name='conf1')
|
conf1 = Config(od, name='conf1')
|
||||||
conf1.property.read_write()
|
conf1.property.read_write()
|
||||||
|
@ -859,7 +859,7 @@ def test_meta_properties_requires_mandatory():
|
||||||
'expected': ParamValue('yes'),
|
'expected': ParamValue('yes'),
|
||||||
'default': ParamValue(None)}))
|
'default': ParamValue(None)}))
|
||||||
ip_eth0 = IPOption('ip_eth0', "ip", Calculation(return_condition, Params(kwargs={'val': ParamOption(ip_address), 'condition': ParamOption(eth0_method), 'expected': ParamValue('dhcp')})), properties=(mandatory_property,))
|
ip_eth0 = IPOption('ip_eth0', "ip", Calculation(return_condition, Params(kwargs={'val': ParamOption(ip_address), 'condition': ParamOption(eth0_method), 'expected': ParamValue('dhcp')})), properties=(mandatory_property,))
|
||||||
ip_gw = IPOption('ip_gw', 'gw', validators=[Calculation(valid_not_equal, Params((ParamOption(ip_eth0), ParamSelfOption())))])
|
ip_gw = IPOption('ip_gw', 'gw', validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(ip_eth0))))])
|
||||||
od = OptionDescription('root', '', [ip_gw, probes, eth0_method, ip_address, ip_eth0])
|
od = OptionDescription('root', '', [ip_gw, probes, eth0_method, ip_address, ip_eth0])
|
||||||
conf1 = Config(od, name='conf1')
|
conf1 = Config(od, name='conf1')
|
||||||
conf1.property.read_write()
|
conf1.property.read_write()
|
||||||
|
|
|
@ -13,13 +13,17 @@ from tiramisu.i18n import _
|
||||||
try:
|
try:
|
||||||
groups.family
|
groups.family
|
||||||
except:
|
except:
|
||||||
groups.family = groups.GroupType('family')
|
groups.addgroup('family')
|
||||||
|
|
||||||
|
|
||||||
def a_func():
|
def a_func():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def display_name(*args):
|
||||||
|
return 'display_name'
|
||||||
|
|
||||||
|
|
||||||
def test_option_valid_name():
|
def test_option_valid_name():
|
||||||
IntOption('test', '')
|
IntOption('test', '')
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
|
@ -76,6 +80,16 @@ def test_option_unknown():
|
||||||
cfg.option('test').value.list()
|
cfg.option('test').value.list()
|
||||||
|
|
||||||
|
|
||||||
|
def test_option_description():
|
||||||
|
description = "it's ok"
|
||||||
|
i = IntOption('test', description)
|
||||||
|
od = OptionDescription('od', 'od', [i])
|
||||||
|
od2 = OptionDescription('od', '', [od])
|
||||||
|
cfg = Config(od2)
|
||||||
|
assert cfg.option('od').option.description() == 'od'
|
||||||
|
assert cfg.option('od.test').option.description() == description
|
||||||
|
|
||||||
|
|
||||||
def test_option_get_information_default():
|
def test_option_get_information_default():
|
||||||
description = "it's ok"
|
description = "it's ok"
|
||||||
string = 'some informations'
|
string = 'some informations'
|
||||||
|
@ -178,7 +192,7 @@ def test_unknown_option():
|
||||||
|
|
||||||
|
|
||||||
def test_optiondescription_list():
|
def test_optiondescription_list():
|
||||||
groups.notfamily1 = groups.GroupType('notfamily1')
|
groups.addgroup('notfamily1')
|
||||||
i = IntOption('test', '')
|
i = IntOption('test', '')
|
||||||
i2 = IntOption('test', '')
|
i2 = IntOption('test', '')
|
||||||
od1 = OptionDescription('od', '', [i])
|
od1 = OptionDescription('od', '', [i])
|
||||||
|
@ -210,7 +224,7 @@ def test_optiondescription_list():
|
||||||
|
|
||||||
|
|
||||||
def test_optiondescription_group():
|
def test_optiondescription_group():
|
||||||
groups.notfamily = groups.GroupType('notfamily')
|
groups.addgroup('notfamily')
|
||||||
i = IntOption('test', '')
|
i = IntOption('test', '')
|
||||||
i2 = IntOption('test', '')
|
i2 = IntOption('test', '')
|
||||||
od1 = OptionDescription('od', '', [i])
|
od1 = OptionDescription('od', '', [i])
|
||||||
|
@ -240,7 +254,7 @@ def test_optiondescription_group():
|
||||||
|
|
||||||
def test_optiondescription_group_redefined():
|
def test_optiondescription_group_redefined():
|
||||||
try:
|
try:
|
||||||
groups.notfamily = groups.GroupType('notfamily')
|
groups.addgroup('notfamily')
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
i = IntOption('test', '')
|
i = IntOption('test', '')
|
||||||
|
@ -301,12 +315,6 @@ def test_intoption():
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
def test_get_display_type():
|
|
||||||
i1 = IntOption('test1', 'description', min_number=3)
|
|
||||||
assert i1.get_display_type() == _('integer')
|
|
||||||
# assert not list_sessions()
|
|
||||||
|
|
||||||
|
|
||||||
def test_option_not_in_config():
|
def test_option_not_in_config():
|
||||||
i1 = IntOption('test1', 'description', min_number=3)
|
i1 = IntOption('test1', 'description', min_number=3)
|
||||||
with pytest.raises(AttributeError):
|
with pytest.raises(AttributeError):
|
||||||
|
@ -322,3 +330,25 @@ def test_option_unknown_func():
|
||||||
cfg = Config(od)
|
cfg = Config(od)
|
||||||
with pytest.raises(ConfigError):
|
with pytest.raises(ConfigError):
|
||||||
cfg.option('test1').value.unknown()
|
cfg.option('test1').value.unknown()
|
||||||
|
|
||||||
|
|
||||||
|
def test_option_with_index():
|
||||||
|
i1 = IntOption('test1', 'description', [4, 5], min_number=3, multi=True)
|
||||||
|
i2 = IntOption('test2', 'description', max_number=3)
|
||||||
|
i3 = IntOption('test3', 'description', min_number=3, max_number=6, warnings_only=True)
|
||||||
|
od = OptionDescription('od', '', [i1, i2, i3])
|
||||||
|
cfg = Config(od)
|
||||||
|
with pytest.raises(ConfigError):
|
||||||
|
cfg.option('test1', 0).value.get()
|
||||||
|
|
||||||
|
|
||||||
|
def test_option_display_name():
|
||||||
|
i1 = IntOption('test1', 'description', min_number=3)
|
||||||
|
i2 = IntOption('test2', 'description', max_number=3)
|
||||||
|
i3 = IntOption('test3', 'description', min_number=3, max_number=6, warnings_only=True)
|
||||||
|
od = OptionDescription('od', '', [i1, i2, i3])
|
||||||
|
cfg = Config(od,
|
||||||
|
display_name=display_name,
|
||||||
|
)
|
||||||
|
assert cfg.option('test1').option.name() == 'test1'
|
||||||
|
assert cfg.option('test1').option.doc() == 'display_name'
|
||||||
|
|
|
@ -145,6 +145,30 @@ def test_hidden_if_in2(config_type):
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def test_hidden_if_in3(config_type):
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
hidden_property = Calculation(calc_value,
|
||||||
|
Params(ParamValue('hidden'),
|
||||||
|
kwargs={'condition': ParamOption(intoption),
|
||||||
|
'expected': ParamValue(1),
|
||||||
|
'default_0': ParamValue(None)}))
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc", properties=(hidden_property,))
|
||||||
|
od1 = OptionDescription('constraints', '', [stroption, intoption])
|
||||||
|
cfg_ori = Config(od1)
|
||||||
|
cfg_ori.property.read_write()
|
||||||
|
cfg = get_config(cfg_ori, config_type)
|
||||||
|
assert not 'hidden' in cfg.option('str').property.get()
|
||||||
|
cfg.option('int').value.set(1)
|
||||||
|
with pytest.raises(PropertiesOptionError):
|
||||||
|
cfg.option('str').value.get()
|
||||||
|
with pytest.raises(PropertiesOptionError):
|
||||||
|
cfg.option('str').value.set('uvw')
|
||||||
|
if config_type == 'tiramisu-api':
|
||||||
|
cfg.send()
|
||||||
|
assert 'hidden' in cfg_ori.unrestraint.option('str').property.get()
|
||||||
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
def test_hidden_if_in_with_group(config_type):
|
def test_hidden_if_in_with_group(config_type):
|
||||||
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
|
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
|
||||||
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
@ -268,7 +292,8 @@ def test_callback(config_type):
|
||||||
assert cfg.option('val1').value.get() == 'val'
|
assert cfg.option('val1').value.get() == 'val'
|
||||||
cfg.option('val1').value.set('new-val')
|
cfg.option('val1').value.set('new-val')
|
||||||
assert cfg.option('val1').value.get() == 'new-val'
|
assert cfg.option('val1').value.get() == 'new-val'
|
||||||
assert cfg.option('val1').option.defaultmulti() == None
|
with pytest.raises(ConfigError):
|
||||||
|
assert cfg.option('val1').option.defaultmulti() == None
|
||||||
cfg.option('val1').value.reset()
|
cfg.option('val1').value.reset()
|
||||||
assert cfg.option('val1').value.get() == 'val'
|
assert cfg.option('val1').value.get() == 'val'
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
@ -1543,3 +1568,8 @@ def test_calc_dependencies(config_type):
|
||||||
assert dep[0].option.get() == val3
|
assert dep[0].option.get() == val3
|
||||||
#
|
#
|
||||||
assert cfg.option('val3').option.dependencies() == []
|
assert cfg.option('val3').option.dependencies() == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_callback__kwargs_wrong(config_type):
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Params(kwargs='string')
|
||||||
|
|
|
@ -60,23 +60,27 @@ def test_mod_read_only_write():
|
||||||
config2 = Config(od1)
|
config2 = Config(od1)
|
||||||
assert config.property.getdefault() == {'cache', 'validator', 'warnings'}
|
assert config.property.getdefault() == {'cache', 'validator', 'warnings'}
|
||||||
assert config.property.getdefault('read_only', 'append') == {'frozen',
|
assert config.property.getdefault('read_only', 'append') == {'frozen',
|
||||||
'disabled',
|
'disabled',
|
||||||
'validator',
|
'validator',
|
||||||
'everything_frozen',
|
'everything_frozen',
|
||||||
'mandatory',
|
'mandatory',
|
||||||
'empty',
|
'empty',
|
||||||
'force_store_value'}
|
'force_store_value',
|
||||||
|
}
|
||||||
assert config.property.getdefault('read_only', 'remove') == {'permissive',
|
assert config.property.getdefault('read_only', 'remove') == {'permissive',
|
||||||
'hidden'}
|
'hidden',
|
||||||
|
}
|
||||||
assert config.property.getdefault('read_write', 'append') == {'frozen',
|
assert config.property.getdefault('read_write', 'append') == {'frozen',
|
||||||
'disabled',
|
'disabled',
|
||||||
'validator',
|
'validator',
|
||||||
'hidden',
|
'hidden',
|
||||||
'force_store_value'}
|
'force_store_value',
|
||||||
|
}
|
||||||
assert config.property.getdefault('read_write', 'remove') == {'permissive',
|
assert config.property.getdefault('read_write', 'remove') == {'permissive',
|
||||||
'everything_frozen',
|
'everything_frozen',
|
||||||
'mandatory',
|
'mandatory',
|
||||||
'empty'}
|
'empty',
|
||||||
|
}
|
||||||
#
|
#
|
||||||
config.property.setdefault(frozenset(['cache']))
|
config.property.setdefault(frozenset(['cache']))
|
||||||
config.property.setdefault(type='read_only', when='append', properties=frozenset(['disabled']))
|
config.property.setdefault(type='read_only', when='append', properties=frozenset(['disabled']))
|
||||||
|
@ -595,6 +599,18 @@ def test_append_properties_force_store_value():
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def test_properties_get_add_reset():
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False, properties=('force_store_value',))
|
||||||
|
gcgroup = OptionDescription('gc', '', [gcdummy])
|
||||||
|
od1 = OptionDescription('tiramisu', '', [gcgroup])
|
||||||
|
cfg = Config(od1)
|
||||||
|
assert cfg.property.get() == {'validator', 'warnings', 'cache'}
|
||||||
|
cfg.property.add('frozen')
|
||||||
|
assert cfg.property.get() == {'validator', 'warnings', 'cache', 'frozen'}
|
||||||
|
cfg.property.reset()
|
||||||
|
assert cfg.property.get() == {'validator', 'warnings', 'cache'}
|
||||||
|
|
||||||
|
|
||||||
def test_reset_properties_force_store_value():
|
def test_reset_properties_force_store_value():
|
||||||
gcdummy = BoolOption('dummy', 'dummy', default=False, properties=('force_store_value',))
|
gcdummy = BoolOption('dummy', 'dummy', default=False, properties=('force_store_value',))
|
||||||
gcgroup = OptionDescription('gc', '', [gcdummy])
|
gcgroup = OptionDescription('gc', '', [gcdummy])
|
||||||
|
@ -683,7 +699,7 @@ def test_pprint():
|
||||||
intoption = IntOption('int', 'Test int option', default=0)
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
hidden_property = Calculation(calc_value,
|
hidden_property = Calculation(calc_value,
|
||||||
Params(ParamValue('hidden'),
|
Params(ParamValue('hidden'),
|
||||||
kwargs={'condition': ParamOption(intoption, todict=True),
|
kwargs={'condition': ParamOption(intoption),
|
||||||
'expected_0': ParamValue(2),
|
'expected_0': ParamValue(2),
|
||||||
'expected_1': ParamValue(3),
|
'expected_1': ParamValue(3),
|
||||||
'expected_2': ParamValue(4),
|
'expected_2': ParamValue(4),
|
||||||
|
@ -691,35 +707,28 @@ def test_pprint():
|
||||||
calc_value_property_help)
|
calc_value_property_help)
|
||||||
disabled_property = Calculation(calc_value,
|
disabled_property = Calculation(calc_value,
|
||||||
Params(ParamValue('disabled'),
|
Params(ParamValue('disabled'),
|
||||||
kwargs={'condition_0': ParamOption(intoption, todict=True),
|
kwargs={'condition_0': ParamOption(intoption),
|
||||||
'expected_0': ParamValue(1),
|
'expected_0': ParamValue(1),
|
||||||
'condition_1': ParamOption(s2, todict=True),
|
'condition_1': ParamOption(s2),
|
||||||
'expected_1': ParamValue('string')}),
|
'expected_1': ParamValue('string')}),
|
||||||
calc_value_property_help)
|
calc_value_property_help)
|
||||||
stroption = StrOption('str', 'Test string option', default="abc", properties=(hidden_property, disabled_property))
|
stroption = StrOption('str', 'Test string option', default="abc", properties=(hidden_property, disabled_property))
|
||||||
# requires=[{'option': intoption, 'expected': 2, 'action': 'hidden', 'inverse': True},
|
|
||||||
# {'option': intoption, 'expected': 3, 'action': 'hidden', 'inverse': True},
|
|
||||||
# {'option': intoption, 'expected': 4, 'action': 'hidden', 'inverse': True},
|
|
||||||
# {'option': intoption, 'expected': 1, 'action': 'disabled'},
|
|
||||||
# {'option': s2, 'expected': 'string', 'action': 'disabled'}])
|
|
||||||
|
|
||||||
val2 = StrOption('val2', "")
|
val2 = StrOption('val2', "")
|
||||||
hidden_property = Calculation(calc_value,
|
hidden_property = Calculation(calc_value,
|
||||||
Params(ParamValue('hidden'),
|
Params(ParamValue('hidden'),
|
||||||
kwargs={'condition': ParamOption(intoption, todict=True),
|
kwargs={'condition': ParamOption(intoption),
|
||||||
'expected': ParamValue(1)}),
|
'expected': ParamValue(1)}),
|
||||||
calc_value_property_help)
|
calc_value_property_help)
|
||||||
descr2 = OptionDescription("options", "options", [val2], properties=(hidden_property,))
|
descr2 = OptionDescription("options", "options", [val2], properties=(hidden_property,))
|
||||||
#descr2 = OptionDescription("options", "", [val2], requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}])
|
|
||||||
|
|
||||||
hidden_property = Calculation(calc_value,
|
hidden_property = Calculation(calc_value,
|
||||||
Params(ParamValue('hidden'),
|
Params(ParamValue('hidden'),
|
||||||
kwargs={'condition': ParamOption(stroption, todict=True),
|
kwargs={'condition': ParamOption(stroption),
|
||||||
'expected': ParamValue('2'),
|
'expected': ParamValue('2'),
|
||||||
'reverse_condition': ParamValue(True)}),
|
'reverse_condition': ParamValue(True)}),
|
||||||
calc_value_property_help)
|
calc_value_property_help)
|
||||||
val3 = StrOption('val3', "", properties=(hidden_property,))
|
val3 = StrOption('val3', "", properties=(hidden_property,))
|
||||||
#val3 = StrOption('val3', "", requires=[{'option': stroption, 'expected': '2', 'action': 'hidden', 'inverse': True}])
|
|
||||||
|
|
||||||
od1 = OptionDescription("options", "root option", [s, s2, s3, intoption, stroption, descr2, val3])
|
od1 = OptionDescription("options", "root option", [s, s2, s3, intoption, stroption, descr2, val3])
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
|
@ -775,3 +784,95 @@ def test_pprint():
|
||||||
assert str(err) == msg_error.format('option', 'string3', prop, '"hidden"')
|
assert str(err) == msg_error.format('option', 'string3', prop, '"hidden"')
|
||||||
del err
|
del err
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def test_pprint_not_todict():
|
||||||
|
msg_error = _("cannot access to {0} \"{1}\" because has {2} {3}")
|
||||||
|
msg_is_not = _('the value of "{0}" is not {1}')
|
||||||
|
msg_is = _('the value of "{0}" is {1}')
|
||||||
|
properties = _('properties')
|
||||||
|
prop = _('property')
|
||||||
|
|
||||||
|
s = StrOption("string", "", default=["string"], default_multi="string", multi=True, properties=('hidden', 'disabled'))
|
||||||
|
s2 = StrOption("string2", "", default="string")
|
||||||
|
s3 = StrOption("string3", "", default=["string"], default_multi="string", multi=True, properties=('hidden',))
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
hidden_property = Calculation(calc_value,
|
||||||
|
Params(ParamValue('hidden'),
|
||||||
|
kwargs={'condition': ParamOption(intoption),
|
||||||
|
'expected_0': ParamValue(2),
|
||||||
|
'expected_1': ParamValue(3),
|
||||||
|
'expected_2': ParamValue(4),
|
||||||
|
'reverse_condition': ParamValue(True)}),
|
||||||
|
)
|
||||||
|
disabled_property = Calculation(calc_value,
|
||||||
|
Params(ParamValue('disabled'),
|
||||||
|
kwargs={'condition_0': ParamOption(intoption),
|
||||||
|
'expected_0': ParamValue(1),
|
||||||
|
'condition_1': ParamOption(s2),
|
||||||
|
'expected_1': ParamValue('string')}),
|
||||||
|
)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc", properties=(hidden_property, disabled_property))
|
||||||
|
|
||||||
|
val2 = StrOption('val2', "")
|
||||||
|
hidden_property = Calculation(calc_value,
|
||||||
|
Params(ParamValue('hidden'),
|
||||||
|
kwargs={'condition': ParamOption(intoption),
|
||||||
|
'expected': ParamValue(1)}),
|
||||||
|
)
|
||||||
|
descr2 = OptionDescription("options", "options", [val2], properties=(hidden_property,))
|
||||||
|
|
||||||
|
hidden_property = Calculation(calc_value,
|
||||||
|
Params(ParamValue('hidden'),
|
||||||
|
kwargs={'condition': ParamOption(stroption),
|
||||||
|
'expected': ParamValue('2'),
|
||||||
|
'reverse_condition': ParamValue(True)}),
|
||||||
|
)
|
||||||
|
val3 = StrOption('val3', "", properties=(hidden_property,))
|
||||||
|
|
||||||
|
od1 = OptionDescription("options", "root option", [s, s2, s3, intoption, stroption, descr2, val3])
|
||||||
|
cfg = Config(od1)
|
||||||
|
cfg.property.read_write()
|
||||||
|
cfg.option('int').value.set(1)
|
||||||
|
err = None
|
||||||
|
try:
|
||||||
|
cfg.option('str').value.get()
|
||||||
|
except PropertiesOptionError as error:
|
||||||
|
err = error
|
||||||
|
|
||||||
|
list_disabled = '"disabled"'
|
||||||
|
list_hidden = '"hidden"'
|
||||||
|
assert str(err) == _(msg_error.format('option', 'Test string option', properties, display_list([list_disabled, list_hidden], add_quote=False)))
|
||||||
|
del err
|
||||||
|
|
||||||
|
err = None
|
||||||
|
try:
|
||||||
|
cfg.option('options.val2').value.get()
|
||||||
|
except PropertiesOptionError as error:
|
||||||
|
err = error
|
||||||
|
|
||||||
|
assert str(err) == msg_error.format('optiondescription', 'options', prop, '"hidden"')
|
||||||
|
|
||||||
|
err = None
|
||||||
|
try:
|
||||||
|
cfg.option('string').value.get()
|
||||||
|
except Exception as error:
|
||||||
|
err = error
|
||||||
|
|
||||||
|
assert str(err) == msg_error.format('option', 'string', properties, display_list(['disabled', 'hidden'], add_quote=True))
|
||||||
|
del err
|
||||||
|
|
||||||
|
err = None
|
||||||
|
try:
|
||||||
|
cfg.option('string3').value.get()
|
||||||
|
except Exception as error:
|
||||||
|
err = error
|
||||||
|
|
||||||
|
assert str(err) == msg_error.format('option', 'string3', prop, '"hidden"')
|
||||||
|
del err
|
||||||
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def test_property_invalid_type():
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
s3 = StrOption("string3", "", default=["string"], default_multi="string", multi=True, properties=(1,))
|
||||||
|
|
|
@ -6,7 +6,8 @@ import pytest
|
||||||
|
|
||||||
from tiramisu import BoolOption, StrOption, IPOption, NetmaskOption, NetworkOption, BroadcastOption, \
|
from tiramisu import BoolOption, StrOption, IPOption, NetmaskOption, NetworkOption, BroadcastOption, \
|
||||||
IntOption, OptionDescription, Leadership, Config, Params, ParamValue, ParamOption, \
|
IntOption, OptionDescription, Leadership, Config, Params, ParamValue, ParamOption, \
|
||||||
ParamSelfOption, ParamIndex, Calculation, valid_ip_netmask, valid_network_netmask, \
|
ParamSelfOption, ParamIndex, ParamInformation, ParamSelfInformation, ParamSelfOption, Calculation, \
|
||||||
|
valid_ip_netmask, valid_network_netmask, \
|
||||||
valid_in_network, valid_broadcast, valid_not_equal, undefined
|
valid_in_network, valid_broadcast, valid_not_equal, undefined
|
||||||
from tiramisu.setting import groups
|
from tiramisu.setting import groups
|
||||||
from tiramisu.error import ValueErrorWarning, ConfigError, PropertiesOptionError
|
from tiramisu.error import ValueErrorWarning, ConfigError, PropertiesOptionError
|
||||||
|
@ -105,11 +106,13 @@ def test_validator(config_type):
|
||||||
assert len(w) == 1
|
assert len(w) == 1
|
||||||
assert str(w[0].message) == msg
|
assert str(w[0].message) == msg
|
||||||
assert cfg.option('opt2').value.valid() is False
|
assert cfg.option('opt2').value.valid() is False
|
||||||
|
#
|
||||||
with warnings.catch_warnings(record=True) as w:
|
with warnings.catch_warnings(record=True) as w:
|
||||||
cfg.option('opt2').value.get()
|
cfg.option('opt2').value.get()
|
||||||
assert len(w) == 1
|
assert len(w) == 1
|
||||||
assert str(w[0].message) == msg
|
assert str(w[0].message) == msg
|
||||||
assert cfg.option('opt2').value.valid() is False
|
assert cfg.option('opt2').value.valid() is False
|
||||||
|
#
|
||||||
with warnings.catch_warnings(record=True) as w:
|
with warnings.catch_warnings(record=True) as w:
|
||||||
cfg.option('opt2').value.get()
|
cfg.option('opt2').value.get()
|
||||||
assert len(w) == 1
|
assert len(w) == 1
|
||||||
|
@ -118,6 +121,13 @@ def test_validator(config_type):
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def test_validator_not_valid(config_type):
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
StrOption('not_a_list', '', validators=Calculation(return_true, Params(ParamSelfOption())), default='val')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
StrOption('not_calculation', '', validators=[str])
|
||||||
|
|
||||||
|
|
||||||
def test_validator_params(config_type):
|
def test_validator_params(config_type):
|
||||||
opt1 = StrOption('opt1', '', validators=[Calculation(return_true, Params((ParamSelfOption(), ParamValue('yes'))))], default='val')
|
opt1 = StrOption('opt1', '', validators=[Calculation(return_true, Params((ParamSelfOption(), ParamValue('yes'))))], default='val')
|
||||||
opt2 = StrOption('opt2', '', validators=[Calculation(return_false, Params((ParamSelfOption(), ParamValue('yes'))))])
|
opt2 = StrOption('opt2', '', validators=[Calculation(return_false, Params((ParamSelfOption(), ParamValue('yes'))))])
|
||||||
|
@ -324,7 +334,14 @@ def test_validator_warning(config_type):
|
||||||
assert len(w) == 1
|
assert len(w) == 1
|
||||||
if config_type != 'tiramisu-api':
|
if config_type != 'tiramisu-api':
|
||||||
assert w[0].message.opt() == opt2
|
assert w[0].message.opt() == opt2
|
||||||
assert str(w[0].message) == msg_err.format('val', opt2._display_name, 'opt2') + ', ' + 'test error return_false'
|
assert str(w[0].message) == msg_err.format('val', opt2.get_type(), 'opt2') + ', ' + 'test error return_false'
|
||||||
|
#
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
|
cfg.nowarnings.option('opt2').value.set('val')
|
||||||
|
assert len(w) == 0
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
|
cfg.option('opt2').value.set('val')
|
||||||
|
assert len(w) == 1
|
||||||
#
|
#
|
||||||
with warnings.catch_warnings(record=True) as w:
|
with warnings.catch_warnings(record=True) as w:
|
||||||
cfg.option('opt3').value.set(['val'])
|
cfg.option('opt3').value.set(['val'])
|
||||||
|
@ -335,7 +352,7 @@ def test_validator_warning(config_type):
|
||||||
assert len(w) == 1
|
assert len(w) == 1
|
||||||
if config_type != 'tiramisu-api':
|
if config_type != 'tiramisu-api':
|
||||||
assert w[0].message.opt() == opt3
|
assert w[0].message.opt() == opt3
|
||||||
assert str(w[0].message) == msg_err.format('val1', opt3._display_name, 'opt3') + ', ' + 'test error'
|
assert str(w[0].message) == msg_err.format('val1', opt3.get_type(), 'opt3') + ', ' + 'test error'
|
||||||
#
|
#
|
||||||
with warnings.catch_warnings(record=True) as w:
|
with warnings.catch_warnings(record=True) as w:
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
|
@ -348,9 +365,9 @@ def test_validator_warning(config_type):
|
||||||
assert len(w) == 2
|
assert len(w) == 2
|
||||||
if config_type != 'tiramisu-api':
|
if config_type != 'tiramisu-api':
|
||||||
assert w[0].message.opt() == opt2
|
assert w[0].message.opt() == opt2
|
||||||
assert str(w[0].message) == msg_err.format('val', opt2._display_name, 'opt2') + ', ' + 'test error return_false'
|
assert str(w[0].message) == msg_err.format('val', opt2.get_type(), 'opt2') + ', ' + 'test error return_false'
|
||||||
assert w[1].message.opt() == opt3
|
assert w[1].message.opt() == opt3
|
||||||
assert str(w[1].message) == msg_err.format('val1', opt3._display_name, 'opt3') + ', ' + 'test error'
|
assert str(w[1].message) == msg_err.format('val1', opt3.get_type(), 'opt3') + ', ' + 'test error'
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
@ -419,13 +436,13 @@ def test_validator_warning_leadership(config_type):
|
||||||
assert len(w) == 1
|
assert len(w) == 1
|
||||||
if config_type != 'tiramisu-api':
|
if config_type != 'tiramisu-api':
|
||||||
assert w[0].message.opt() == netmask_admin_eth0
|
assert w[0].message.opt() == netmask_admin_eth0
|
||||||
assert str(w[0].message) == msg_err.format('val1', netmask_admin_eth0._display_name, display_name_netmask) + ', test error'
|
assert str(w[0].message) == msg_err.format('val1', netmask_admin_eth0.get_type(), display_name_netmask) + ', test error'
|
||||||
#
|
#
|
||||||
with warnings.catch_warnings(record=True) as w:
|
with warnings.catch_warnings(record=True) as w:
|
||||||
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val'])
|
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val'])
|
||||||
if config_type != 'tiramisu-api':
|
if config_type != 'tiramisu-api':
|
||||||
assert w[0].message.opt() == ip_admin_eth0
|
assert w[0].message.opt() == ip_admin_eth0
|
||||||
assert str(w[0].message) == msg_err.format('val', ip_admin_eth0._display_name, display_name_ip) + ', test error return_false'
|
assert str(w[0].message) == msg_err.format('val', ip_admin_eth0.get_type(), display_name_ip) + ', test error return_false'
|
||||||
else:
|
else:
|
||||||
assert len(w) == 2
|
assert len(w) == 2
|
||||||
#
|
#
|
||||||
|
@ -433,7 +450,7 @@ def test_validator_warning_leadership(config_type):
|
||||||
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val', 'val1', 'val1'])
|
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val', 'val1', 'val1'])
|
||||||
if config_type != 'tiramisu-api':
|
if config_type != 'tiramisu-api':
|
||||||
assert w[0].message.opt() == ip_admin_eth0
|
assert w[0].message.opt() == ip_admin_eth0
|
||||||
assert str(w[0].message) == msg_err.format('val', ip_admin_eth0._display_name, display_name_ip) + ', test error return_false'
|
assert str(w[0].message) == msg_err.format('val', ip_admin_eth0.get_type(), display_name_ip) + ', test error return_false'
|
||||||
else:
|
else:
|
||||||
assert len(w) == 3
|
assert len(w) == 3
|
||||||
#
|
#
|
||||||
|
@ -441,7 +458,7 @@ def test_validator_warning_leadership(config_type):
|
||||||
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val1', 'val', 'val1'])
|
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val1', 'val', 'val1'])
|
||||||
if config_type != 'tiramisu-api':
|
if config_type != 'tiramisu-api':
|
||||||
assert w[0].message.opt() == ip_admin_eth0
|
assert w[0].message.opt() == ip_admin_eth0
|
||||||
assert str(w[0].message) == msg_err.format('val', ip_admin_eth0._display_name, display_name_ip) + ', test error return_false'
|
assert str(w[0].message) == msg_err.format('val', ip_admin_eth0.get_type(), display_name_ip) + ', test error return_false'
|
||||||
else:
|
else:
|
||||||
assert len(w) == 3
|
assert len(w) == 3
|
||||||
#
|
#
|
||||||
|
@ -450,7 +467,7 @@ def test_validator_warning_leadership(config_type):
|
||||||
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val1', 'val1', 'val'])
|
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val1', 'val1', 'val'])
|
||||||
if config_type != 'tiramisu-api':
|
if config_type != 'tiramisu-api':
|
||||||
assert w[0].message.opt() == ip_admin_eth0
|
assert w[0].message.opt() == ip_admin_eth0
|
||||||
assert str(w[0].message) == msg_err.format('val', ip_admin_eth0._display_name, display_name_ip) + ', test error return_false'
|
assert str(w[0].message) == msg_err.format('val', ip_admin_eth0.get_type(), display_name_ip) + ', test error return_false'
|
||||||
else:
|
else:
|
||||||
assert len(w) == 3
|
assert len(w) == 3
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
@ -494,11 +511,12 @@ def test_validator_dependencies():
|
||||||
|
|
||||||
def test_validator_ip_netmask(config_type):
|
def test_validator_ip_netmask(config_type):
|
||||||
a = IPOption('a', '')
|
a = IPOption('a', '')
|
||||||
b = NetmaskOption('b', '', validators=[Calculation(valid_ip_netmask, Params((ParamOption(a, todict=True), ParamSelfOption())))])
|
b = NetmaskOption('b', '', validators=[Calculation(valid_ip_netmask, Params((ParamOption(a), ParamSelfOption())))])
|
||||||
od1 = OptionDescription('od', '', [a, b])
|
od1 = OptionDescription('od', '', [a, b])
|
||||||
cfg_ori = Config(od1)
|
cfg_ori = Config(od1)
|
||||||
cfg = cfg_ori
|
cfg = cfg_ori
|
||||||
cfg = get_config(cfg_ori, config_type)
|
cfg = get_config(cfg_ori, config_type)
|
||||||
|
cfg.option('b').value.set('255.255.255.0')
|
||||||
cfg.option('a').value.set('192.168.1.1')
|
cfg.option('a').value.set('192.168.1.1')
|
||||||
cfg.option('b').value.set('255.255.255.0')
|
cfg.option('b').value.set('255.255.255.0')
|
||||||
cfg.option('a').value.set('192.168.1.2')
|
cfg.option('a').value.set('192.168.1.2')
|
||||||
|
@ -528,7 +546,7 @@ def test_validator_ip_netmask(config_type):
|
||||||
|
|
||||||
def test_validator_network_netmask(config_type):
|
def test_validator_network_netmask(config_type):
|
||||||
a = NetworkOption('a', '')
|
a = NetworkOption('a', '')
|
||||||
b = NetmaskOption('b', '', validators=[Calculation(valid_network_netmask, Params((ParamOption(a, todict=True), ParamSelfOption())))])
|
b = NetmaskOption('b', '', validators=[Calculation(valid_network_netmask, Params((ParamOption(a), ParamSelfOption())))])
|
||||||
od1 = OptionDescription('od', '', [a, b])
|
od1 = OptionDescription('od', '', [a, b])
|
||||||
cfg_ori = Config(od1)
|
cfg_ori = Config(od1)
|
||||||
cfg = get_config(cfg_ori, config_type)
|
cfg = get_config(cfg_ori, config_type)
|
||||||
|
@ -557,8 +575,8 @@ def test_validator_network_netmask(config_type):
|
||||||
def test_validator_ip_in_network(config_type):
|
def test_validator_ip_in_network(config_type):
|
||||||
a = NetworkOption('a', '')
|
a = NetworkOption('a', '')
|
||||||
b = NetmaskOption('b', '')
|
b = NetmaskOption('b', '')
|
||||||
c = IPOption('c', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True), ParamOption(b, todict=True))))])
|
c = IPOption('c', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a), ParamOption(b))))])
|
||||||
d = IPOption('d', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True), ParamOption(b, todict=True))), warnings_only=True)])
|
d = IPOption('d', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a), ParamOption(b))), warnings_only=True)])
|
||||||
od1 = OptionDescription('od', '', [a, b, c, d])
|
od1 = OptionDescription('od', '', [a, b, c, d])
|
||||||
warnings.simplefilter("always", ValueErrorWarning)
|
warnings.simplefilter("always", ValueErrorWarning)
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
|
@ -581,8 +599,8 @@ def test_validator_ip_in_network(config_type):
|
||||||
def test_validator_ip_in_network_incomplete(config_type):
|
def test_validator_ip_in_network_incomplete(config_type):
|
||||||
a = NetworkOption('a', '')
|
a = NetworkOption('a', '')
|
||||||
b = NetmaskOption('b', '')
|
b = NetmaskOption('b', '')
|
||||||
c = IPOption('c', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True), ParamOption(b, todict=True))))])
|
c = IPOption('c', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a), ParamOption(b))))])
|
||||||
d = IPOption('d', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True), ParamOption(b, todict=True))), warnings_only=True)])
|
d = IPOption('d', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a), ParamOption(b))), warnings_only=True)])
|
||||||
od1 = OptionDescription('od', '', [a, b, c, d])
|
od1 = OptionDescription('od', '', [a, b, c, d])
|
||||||
warnings.simplefilter("always", ValueErrorWarning)
|
warnings.simplefilter("always", ValueErrorWarning)
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
|
@ -603,8 +621,8 @@ def test_validator_ip_in_network_incomplete(config_type):
|
||||||
|
|
||||||
def test_validator_ip_in_network_cidr(config_type):
|
def test_validator_ip_in_network_cidr(config_type):
|
||||||
a = NetworkOption('a', '', cidr=True)
|
a = NetworkOption('a', '', cidr=True)
|
||||||
c = IPOption('c', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True))))])
|
c = IPOption('c', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a))))])
|
||||||
d = IPOption('d', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True))), warnings_only=True)])
|
d = IPOption('d', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a))), warnings_only=True)])
|
||||||
od1 = OptionDescription('od', '', [a, c, d])
|
od1 = OptionDescription('od', '', [a, c, d])
|
||||||
warnings.simplefilter("always", ValueErrorWarning)
|
warnings.simplefilter("always", ValueErrorWarning)
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
|
@ -625,8 +643,8 @@ def test_validator_ip_in_network_cidr(config_type):
|
||||||
|
|
||||||
def test_validator_ip_in_network_cidr_incomplete(config_type):
|
def test_validator_ip_in_network_cidr_incomplete(config_type):
|
||||||
a = NetworkOption('a', '', cidr=True)
|
a = NetworkOption('a', '', cidr=True)
|
||||||
c = IPOption('c', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True))))])
|
c = IPOption('c', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a))))])
|
||||||
d = IPOption('d', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True))), warnings_only=True)])
|
d = IPOption('d', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a))), warnings_only=True)])
|
||||||
od1 = OptionDescription('od', '', [a, c, d])
|
od1 = OptionDescription('od', '', [a, c, d])
|
||||||
warnings.simplefilter("always", ValueErrorWarning)
|
warnings.simplefilter("always", ValueErrorWarning)
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
|
@ -643,7 +661,7 @@ def test_validator_ip_in_network_cidr_incomplete(config_type):
|
||||||
|
|
||||||
def test_validator_ip_netmask_multi(config_type):
|
def test_validator_ip_netmask_multi(config_type):
|
||||||
a = IPOption('a', '', multi=True)
|
a = IPOption('a', '', multi=True)
|
||||||
b = NetmaskOption('b', '', multi=True, validators=[Calculation(valid_ip_netmask, Params((ParamOption(a, todict=True), ParamSelfOption())))])
|
b = NetmaskOption('b', '', multi=True, validators=[Calculation(valid_ip_netmask, Params((ParamOption(a), ParamSelfOption())))])
|
||||||
od = Leadership('a', '', [a, b])
|
od = Leadership('a', '', [a, b])
|
||||||
od2 = OptionDescription('od2', '', [od])
|
od2 = OptionDescription('od2', '', [od])
|
||||||
cfg_ori = Config(od2)
|
cfg_ori = Config(od2)
|
||||||
|
@ -886,6 +904,39 @@ def test_validator_broadcast(config_type):
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def test_validator_broadcast_todict(config_type):
|
||||||
|
a = NetworkOption('a', '', multi=True)
|
||||||
|
b = NetmaskOption('b', '', multi=True, validators=[Calculation(valid_network_netmask, Params((ParamOption(a), ParamSelfOption())))])
|
||||||
|
c = BroadcastOption('c', '', multi=True, validators=[Calculation(valid_broadcast, Params((ParamOption(a), ParamOption(b), ParamSelfOption())))])
|
||||||
|
od = Leadership('a', '', [a, b, c])
|
||||||
|
od2 = OptionDescription('od2', '', [od])
|
||||||
|
cfg = Config(od2)
|
||||||
|
cfg = get_config(cfg, config_type)
|
||||||
|
#first, test network_netmask
|
||||||
|
cfg.option('a.a').value.set(['192.168.1.128'])
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
cfg.option('a.a').value.set(['255.255.255.0'])
|
||||||
|
#
|
||||||
|
cfg.option('a.a').value.set(['192.168.1.0'])
|
||||||
|
cfg.option('a.b', 0).value.set('255.255.255.0')
|
||||||
|
cfg.option('a.c', 0).value.set('192.168.1.255')
|
||||||
|
cfg.option('a.a').value.set(['192.168.1.1'])
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
cfg.option('a.b', 0).value.get()
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
cfg.option('a.c', 0).value.get()
|
||||||
|
#
|
||||||
|
cfg.option('a.a').value.set(['192.168.1.0', '192.168.2.128'])
|
||||||
|
cfg.option('a.b', 0).value.set('255.255.255.0')
|
||||||
|
cfg.option('a.b', 1).value.set('255.255.255.128')
|
||||||
|
cfg.option('a.c', 0).value.set('192.168.1.255')
|
||||||
|
cfg.option('a.c', 1).value.set('192.168.2.255')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
cfg.option('a.c', 1).value.set('192.168.2.128')
|
||||||
|
cfg.option('a.c', 1).value.set('192.168.2.255')
|
||||||
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
def test_validator_broadcast_warnings(config_type):
|
def test_validator_broadcast_warnings(config_type):
|
||||||
warnings.simplefilter("always", ValueErrorWarning)
|
warnings.simplefilter("always", ValueErrorWarning)
|
||||||
a = NetworkOption('a', '', properties=('mandatory', 'disabled'))
|
a = NetworkOption('a', '', properties=('mandatory', 'disabled'))
|
||||||
|
@ -969,7 +1020,7 @@ def test_validator_has_dependency():
|
||||||
def test_validator_warnings_only_more_option(config_type):
|
def test_validator_warnings_only_more_option(config_type):
|
||||||
a = IntOption('a', '')
|
a = IntOption('a', '')
|
||||||
b = IntOption('b', '')
|
b = IntOption('b', '')
|
||||||
d = IntOption('d', '', validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True), ParamOption(b, todict=True))), warnings_only=True)])
|
d = IntOption('d', '', validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a), ParamOption(b))), warnings_only=True)])
|
||||||
od1 = OptionDescription('od', '', [a, b, d])
|
od1 = OptionDescription('od', '', [a, b, d])
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
cfg = get_config(cfg, config_type)
|
cfg = get_config(cfg, config_type)
|
||||||
|
@ -988,7 +1039,7 @@ def test_validator_warnings_only_more_option(config_type):
|
||||||
|
|
||||||
def test_validator_error_prefix():
|
def test_validator_error_prefix():
|
||||||
a = IntOption('a', '')
|
a = IntOption('a', '')
|
||||||
b = IntOption('b', '', validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True))))])
|
b = IntOption('b', '', validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a))))])
|
||||||
od1 = OptionDescription('od', '', [a, b])
|
od1 = OptionDescription('od', '', [a, b])
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
cfg.option('a').value.set(1)
|
cfg.option('a').value.set(1)
|
||||||
|
@ -1006,7 +1057,7 @@ def test_validator_error_prefix():
|
||||||
|
|
||||||
def test_validator_warnings_only_option(config_type):
|
def test_validator_warnings_only_option(config_type):
|
||||||
a = IntOption('a', '')
|
a = IntOption('a', '')
|
||||||
b = IntOption('b', '', warnings_only=True, validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True))))])
|
b = IntOption('b', '', warnings_only=True, validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a))))])
|
||||||
od1 = OptionDescription('od', '', [a, b])
|
od1 = OptionDescription('od', '', [a, b])
|
||||||
cfg_ori = Config(od1)
|
cfg_ori = Config(od1)
|
||||||
cfg = get_config(cfg_ori, config_type)
|
cfg = get_config(cfg_ori, config_type)
|
||||||
|
@ -1086,7 +1137,7 @@ def test_validator_not_equal_leadership_default():
|
||||||
|
|
||||||
def test_validator_default_diff():
|
def test_validator_default_diff():
|
||||||
a = IntOption('a', '', 3)
|
a = IntOption('a', '', 3)
|
||||||
b = IntOption('b', '', 1, validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True))))])
|
b = IntOption('b', '', 1, validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a))))])
|
||||||
od1 = OptionDescription('od', '', [a, b])
|
od1 = OptionDescription('od', '', [a, b])
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
# FIXME cfg = get_config(cfg, config_type)
|
# FIXME cfg = get_config(cfg, config_type)
|
||||||
|
@ -1107,7 +1158,7 @@ def test_validator_default_diff():
|
||||||
|
|
||||||
def test_validator_permissive(config_type):
|
def test_validator_permissive(config_type):
|
||||||
a = IntOption('a', '', 1, properties=('hidden',))
|
a = IntOption('a', '', 1, properties=('hidden',))
|
||||||
b = IntOption('b', '', 2, validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True))))])
|
b = IntOption('b', '', 2, validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a))))])
|
||||||
od1 = OptionDescription('od', '', [a, b])
|
od1 = OptionDescription('od', '', [a, b])
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
cfg.property.read_write()
|
cfg.property.read_write()
|
||||||
|
@ -1121,7 +1172,7 @@ def test_validator_permissive(config_type):
|
||||||
|
|
||||||
def test_validator_disabled(config_type):
|
def test_validator_disabled(config_type):
|
||||||
a = IntOption('a', '', 1, properties=('disabled',))
|
a = IntOption('a', '', 1, properties=('disabled',))
|
||||||
b = IntOption('b', '', 2, validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True, raisepropertyerror=True))))])
|
b = IntOption('b', '', 2, validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, raisepropertyerror=True))))])
|
||||||
od1 = OptionDescription('od', '', [a, b])
|
od1 = OptionDescription('od', '', [a, b])
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
cfg.property.read_write()
|
cfg.property.read_write()
|
||||||
|
@ -1133,7 +1184,7 @@ def test_validator_disabled(config_type):
|
||||||
|
|
||||||
def test_consistency_disabled_transitive(config_type):
|
def test_consistency_disabled_transitive(config_type):
|
||||||
a = IntOption('a', '', 1, properties=('disabled',))
|
a = IntOption('a', '', 1, properties=('disabled',))
|
||||||
b = IntOption('b', '', 2, validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True, notraisepropertyerror=True))))])
|
b = IntOption('b', '', 2, validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, notraisepropertyerror=True))))])
|
||||||
od1 = OptionDescription('od', '', [a, b])
|
od1 = OptionDescription('od', '', [a, b])
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
cfg.property.read_write()
|
cfg.property.read_write()
|
||||||
|
@ -1145,7 +1196,7 @@ def test_consistency_disabled_transitive(config_type):
|
||||||
def test_consistency_double_warnings(config_type):
|
def test_consistency_double_warnings(config_type):
|
||||||
a = IntOption('a', '', 1)
|
a = IntOption('a', '', 1)
|
||||||
b = IntOption('b', '', 1)
|
b = IntOption('b', '', 1)
|
||||||
c = IntOption('c', '', validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True))), warnings_only=True), Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(b, todict=True))), warnings_only=True)])
|
c = IntOption('c', '', validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a))), warnings_only=True), Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(b))), warnings_only=True)])
|
||||||
od = OptionDescription('od', '', [a, b, c])
|
od = OptionDescription('od', '', [a, b, c])
|
||||||
warnings.simplefilter("always", ValueErrorWarning)
|
warnings.simplefilter("always", ValueErrorWarning)
|
||||||
od1 = OptionDescription('od2', '', [od])
|
od1 = OptionDescription('od2', '', [od])
|
||||||
|
@ -1179,8 +1230,8 @@ def test_consistency_warnings_error(config_type):
|
||||||
a = IntOption('a', '', 1)
|
a = IntOption('a', '', 1)
|
||||||
b = IntOption('b', '', 1)
|
b = IntOption('b', '', 1)
|
||||||
c = IntOption('c', '', validators=[
|
c = IntOption('c', '', validators=[
|
||||||
Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True))), warnings_only=True),
|
Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a))), warnings_only=True),
|
||||||
Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(b, todict=True))))
|
Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(b))))
|
||||||
])
|
])
|
||||||
od1 = OptionDescription('od', '', [a, b, c])
|
od1 = OptionDescription('od', '', [a, b, c])
|
||||||
warnings.simplefilter("always", ValueErrorWarning)
|
warnings.simplefilter("always", ValueErrorWarning)
|
||||||
|
@ -1196,7 +1247,7 @@ def test_consistency_warnings_error(config_type):
|
||||||
def test_consistency_not_equal_has_dependency():
|
def test_consistency_not_equal_has_dependency():
|
||||||
a = IntOption('a', '')
|
a = IntOption('a', '')
|
||||||
b = IntOption('b', '', )
|
b = IntOption('b', '', )
|
||||||
b = IntOption('b', '', validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a, todict=True))))])
|
b = IntOption('b', '', validators=[Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a))))])
|
||||||
od1 = OptionDescription('od', '', [a, b])
|
od1 = OptionDescription('od', '', [a, b])
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
assert cfg.option('a').option.has_dependency() is False
|
assert cfg.option('a').option.has_dependency() is False
|
||||||
|
@ -1204,3 +1255,25 @@ def test_consistency_not_equal_has_dependency():
|
||||||
assert cfg.option('a').option.has_dependency(False) is True
|
assert cfg.option('a').option.has_dependency(False) is True
|
||||||
assert cfg.option('b').option.has_dependency(False) is False
|
assert cfg.option('b').option.has_dependency(False) is False
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def test_validator_information(config_type):
|
||||||
|
opt1 = StrOption('opt1', '', validators=[Calculation(return_true, Params((ParamSelfInformation('key'), ParamValue('yes'))))], default='val')
|
||||||
|
opt2 = StrOption('opt2', '', validators=[Calculation(return_true, Params((ParamInformation('key'), ParamValue('yes'))))], default='val')
|
||||||
|
od1 = OptionDescription('root', '', [opt1, opt2])
|
||||||
|
cfg = Config(od1)
|
||||||
|
with pytest.raises(ConfigError):
|
||||||
|
cfg.option('opt1').value.get()
|
||||||
|
cfg.option('opt1').information.set('key', 'val')
|
||||||
|
assert cfg.option('opt1').value.get() == 'val'
|
||||||
|
cfg.option('opt1').information.set('key', 'val1')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
cfg.option('opt1').value.get()
|
||||||
|
#
|
||||||
|
with pytest.raises(ConfigError):
|
||||||
|
assert cfg.option('opt2').value.get()
|
||||||
|
cfg.information.set('key', 'val')
|
||||||
|
assert cfg.option('opt2').value.get() == 'val'
|
||||||
|
cfg.information.set('key', 'val1')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
cfg.option('opt2').value.get()
|
||||||
|
|
|
@ -56,7 +56,7 @@ def test_requires(config_type):
|
||||||
a = BoolOption('activate_service', '', True)
|
a = BoolOption('activate_service', '', True)
|
||||||
disabled_property = Calculation(calc_value,
|
disabled_property = Calculation(calc_value,
|
||||||
Params(ParamValue('disabled'),
|
Params(ParamValue('disabled'),
|
||||||
kwargs={'condition': ParamOption(a, todict=True),
|
kwargs={'condition': ParamOption(a),
|
||||||
'expected': ParamValue(False)}))
|
'expected': ParamValue(False)}))
|
||||||
b = IPOption('ip_address_service', '',
|
b = IPOption('ip_address_service', '',
|
||||||
properties=(disabled_property,))
|
properties=(disabled_property,))
|
||||||
|
@ -81,7 +81,7 @@ def test_requires_inverse(config_type):
|
||||||
a = BoolOption('activate_service', '', True)
|
a = BoolOption('activate_service', '', True)
|
||||||
disabled_property = Calculation(calc_value,
|
disabled_property = Calculation(calc_value,
|
||||||
Params(ParamValue('disabled'),
|
Params(ParamValue('disabled'),
|
||||||
kwargs={'condition': ParamOption(a, todict=True),
|
kwargs={'condition': ParamOption(a),
|
||||||
'expected': ParamValue(False),
|
'expected': ParamValue(False),
|
||||||
'reverse_condition': ParamValue(True)}))
|
'reverse_condition': ParamValue(True)}))
|
||||||
b = IPOption('ip_address_service', '', properties=(disabled_property,))
|
b = IPOption('ip_address_service', '', properties=(disabled_property,))
|
||||||
|
@ -158,13 +158,13 @@ def test_requires_same_action(config_type):
|
||||||
activate_service = BoolOption('activate_service', '', True)
|
activate_service = BoolOption('activate_service', '', True)
|
||||||
new_property = Calculation(calc_value,
|
new_property = Calculation(calc_value,
|
||||||
Params(ParamValue('new'),
|
Params(ParamValue('new'),
|
||||||
kwargs={'condition': ParamOption(activate_service, todict=True),
|
kwargs={'condition': ParamOption(activate_service),
|
||||||
'expected': ParamValue(False)}),
|
'expected': ParamValue(False)}),
|
||||||
calc_value_property_help)
|
calc_value_property_help)
|
||||||
activate_service_web = BoolOption('activate_service_web', '', True, properties=(new_property,))
|
activate_service_web = BoolOption('activate_service_web', '', True, properties=(new_property,))
|
||||||
disabled_property = Calculation(calc_value,
|
disabled_property = Calculation(calc_value,
|
||||||
Params(ParamValue('disabled'),
|
Params(ParamValue('disabled'),
|
||||||
kwargs={'condition': ParamOption(activate_service_web, notraisepropertyerror=True, todict=True),
|
kwargs={'condition': ParamOption(activate_service_web, notraisepropertyerror=True),
|
||||||
'expected': ParamValue(False)}),
|
'expected': ParamValue(False)}),
|
||||||
calc_value_property_help)
|
calc_value_property_help)
|
||||||
ip_address_service_web = IPOption('ip_address_service_web', '', properties=(disabled_property,))
|
ip_address_service_web = IPOption('ip_address_service_web', '', properties=(disabled_property,))
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
from .autopath import do_autopath
|
|
||||||
do_autopath()
|
|
||||||
from tiramisu import BoolOption, StrOption, SymLinkOption, OptionDescription, DynOptionDescription, \
|
|
||||||
Calculation, Params, ParamOption, ParamValue, calc_value, Config
|
|
||||||
from pickle import dumps
|
|
||||||
import pytest
|
|
||||||
import sys, warnings
|
|
||||||
|
|
||||||
|
|
||||||
def test_diff_opt():
|
|
||||||
b = BoolOption('b', '')
|
|
||||||
disabled_property = Calculation(calc_value,
|
|
||||||
Params(ParamValue('disabled'),
|
|
||||||
kwargs={'condition': ParamOption(b),
|
|
||||||
'expected': ParamValue(True),
|
|
||||||
'reverse_condition': ParamValue(True)}))
|
|
||||||
u = StrOption('u', '', properties=(disabled_property,))
|
|
||||||
s = SymLinkOption('s', u)
|
|
||||||
o = OptionDescription('o', '', [b, u, s])
|
|
||||||
o1 = OptionDescription('o1', '', [o])
|
|
||||||
|
|
||||||
with pytest.raises(NotImplementedError):
|
|
||||||
dumps(o1)
|
|
||||||
|
|
||||||
|
|
||||||
def test_diff_information_config():
|
|
||||||
b = BoolOption('b', '')
|
|
||||||
b.impl_set_information('info', 'oh')
|
|
||||||
b.impl_set_information('info1', 'oh')
|
|
||||||
b.impl_set_information('info2', 'oh')
|
|
||||||
o = OptionDescription('o', '', [b])
|
|
||||||
od1 = OptionDescription('o1', '', [o])
|
|
||||||
cfg = Config(od1)
|
|
||||||
c = cfg._config_bag.context
|
|
||||||
with pytest.raises(NotImplementedError):
|
|
||||||
dumps(c)
|
|
||||||
# assert not list_sessions()
|
|
||||||
|
|
||||||
|
|
||||||
def test_only_optiondescription():
|
|
||||||
b = BoolOption('b', '')
|
|
||||||
b
|
|
||||||
with pytest.raises(NotImplementedError):
|
|
||||||
dumps(b)
|
|
|
@ -8,7 +8,7 @@ import warnings
|
||||||
from tiramisu.setting import groups, owners
|
from tiramisu.setting import groups, owners
|
||||||
from tiramisu import StrOption, IntOption, OptionDescription, submulti, Leadership, Config, \
|
from tiramisu import StrOption, IntOption, OptionDescription, submulti, Leadership, Config, \
|
||||||
MetaConfig, undefined, Params, ParamOption, Calculation
|
MetaConfig, undefined, Params, ParamOption, Calculation
|
||||||
from tiramisu.error import LeadershipError
|
from tiramisu.error import LeadershipError, PropertiesOptionError
|
||||||
|
|
||||||
|
|
||||||
def return_val(val=None):
|
def return_val(val=None):
|
||||||
|
@ -48,6 +48,51 @@ def test_submulti():
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def test_submulti_mandatory():
|
||||||
|
multi = StrOption('multi', '', multi=submulti, properties=('mandatory',))
|
||||||
|
od1 = OptionDescription('od', '', [multi])
|
||||||
|
cfg = Config(od1)
|
||||||
|
cfg.property.read_only()
|
||||||
|
with pytest.raises(PropertiesOptionError):
|
||||||
|
cfg.option('multi').value.get()
|
||||||
|
#
|
||||||
|
cfg.property.read_write()
|
||||||
|
cfg.option('multi').value.set([['val']])
|
||||||
|
cfg.property.read_only()
|
||||||
|
assert cfg.option('multi').value.get() == [['val']]
|
||||||
|
#
|
||||||
|
cfg.property.read_write()
|
||||||
|
cfg.option('multi').value.set([['val'], ['']])
|
||||||
|
cfg.property.read_only()
|
||||||
|
with pytest.raises(PropertiesOptionError):
|
||||||
|
cfg.option('multi').value.get()
|
||||||
|
#
|
||||||
|
cfg.property.read_write()
|
||||||
|
cfg.option('multi').value.set([['val'], [None]])
|
||||||
|
cfg.property.read_only()
|
||||||
|
with pytest.raises(PropertiesOptionError):
|
||||||
|
cfg.option('multi').value.get()
|
||||||
|
#
|
||||||
|
cfg.property.read_write()
|
||||||
|
cfg.option('multi').value.set([['val'], []])
|
||||||
|
cfg.property.read_only()
|
||||||
|
with pytest.raises(PropertiesOptionError):
|
||||||
|
cfg.option('multi').value.get()
|
||||||
|
#
|
||||||
|
cfg.property.read_write()
|
||||||
|
cfg.option('multi').value.set([['val'], ['val1', '']])
|
||||||
|
cfg.property.read_only()
|
||||||
|
with pytest.raises(PropertiesOptionError):
|
||||||
|
cfg.option('multi').value.get()
|
||||||
|
#
|
||||||
|
cfg.property.read_write()
|
||||||
|
cfg.option('multi').value.set([['val'], ['val1', '', 'val2']])
|
||||||
|
cfg.property.read_only()
|
||||||
|
with pytest.raises(PropertiesOptionError):
|
||||||
|
cfg.option('multi').value.get()
|
||||||
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
def test_submulti_default_multi_not_list():
|
def test_submulti_default_multi_not_list():
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
StrOption('multi2', '', default_multi='yes', multi=submulti)
|
StrOption('multi2', '', default_multi='yes', multi=submulti)
|
||||||
|
@ -235,6 +280,50 @@ def test_values_with_leader_and_followers_submulti():
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def test_values_with_leader_and_followers_submulti_mandatory():
|
||||||
|
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||||
|
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=submulti, properties=('mandatory',))
|
||||||
|
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||||
|
od1 = OptionDescription('toto', '', [interface1])
|
||||||
|
cfg = Config(od1)
|
||||||
|
cfg.property.read_only()
|
||||||
|
owner = cfg.owner.get()
|
||||||
|
assert interface1.impl_get_group_type() == groups.leadership
|
||||||
|
assert cfg.option('ip_admin_eth0.ip_admin_eth0').owner.get() == owners.default
|
||||||
|
assert cfg.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
|
||||||
|
#
|
||||||
|
cfg.property.read_write()
|
||||||
|
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(["192.168.230.145"])
|
||||||
|
cfg.property.read_only()
|
||||||
|
assert cfg.option('ip_admin_eth0.ip_admin_eth0').value.get() == ["192.168.230.145"]
|
||||||
|
with pytest.raises(PropertiesOptionError):
|
||||||
|
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()
|
||||||
|
#
|
||||||
|
cfg.property.read_write()
|
||||||
|
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set(["255.255.255.0"])
|
||||||
|
cfg.property.read_only()
|
||||||
|
assert cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == ["255.255.255.0"]
|
||||||
|
#
|
||||||
|
cfg.property.read_write()
|
||||||
|
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set(["255.255.255.0", None])
|
||||||
|
cfg.property.read_only()
|
||||||
|
with pytest.raises(PropertiesOptionError):
|
||||||
|
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()
|
||||||
|
#
|
||||||
|
cfg.property.read_write()
|
||||||
|
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set(["255.255.255.0", ''])
|
||||||
|
cfg.property.read_only()
|
||||||
|
with pytest.raises(PropertiesOptionError):
|
||||||
|
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()
|
||||||
|
#
|
||||||
|
cfg.property.read_write()
|
||||||
|
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set(["255.255.255.0", '', "255.255.255.0"])
|
||||||
|
cfg.property.read_only()
|
||||||
|
with pytest.raises(PropertiesOptionError):
|
||||||
|
cfg.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()
|
||||||
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
def test_values_with_leader_and_followers_submulti_default_multi():
|
def test_values_with_leader_and_followers_submulti_default_multi():
|
||||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=submulti, default_multi=['255.255.0.0', '0.0.0.0'])
|
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=submulti, default_multi=['255.255.0.0', '0.0.0.0'])
|
||||||
|
|
|
@ -4,10 +4,11 @@ from .autopath import do_autopath
|
||||||
do_autopath()
|
do_autopath()
|
||||||
from .config import config_type, get_config
|
from .config import config_type, get_config
|
||||||
|
|
||||||
from tiramisu import BoolOption, StrOption, SymLinkOption, \
|
from tiramisu import BoolOption, StrOption, SymLinkOption, submulti, \
|
||||||
OptionDescription, Leadership, Config, Calculation, calc_value, Params, ParamOption, ParamValue
|
OptionDescription, Leadership, Config, Calculation, calc_value, Params, ParamOption, ParamValue
|
||||||
from tiramisu.error import PropertiesOptionError, ConfigError
|
from tiramisu.error import PropertiesOptionError, ConfigError
|
||||||
from tiramisu.setting import groups, owners
|
from tiramisu.setting import groups, owners
|
||||||
|
from tiramisu.i18n import _
|
||||||
|
|
||||||
|
|
||||||
def return_value():
|
def return_value():
|
||||||
|
@ -19,9 +20,14 @@ def test_symlink_option(config_type):
|
||||||
boolopt = BoolOption("b", "", default=False)
|
boolopt = BoolOption("b", "", default=False)
|
||||||
linkopt = SymLinkOption("c", boolopt)
|
linkopt = SymLinkOption("c", boolopt)
|
||||||
od1 = OptionDescription("opt", "",
|
od1 = OptionDescription("opt", "",
|
||||||
[linkopt, OptionDescription("s1", "", [boolopt])])
|
[linkopt, OptionDescription("s1", "", [boolopt])],
|
||||||
|
)
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
cfg = get_config(cfg, config_type)
|
cfg = get_config(cfg, config_type)
|
||||||
|
assert not cfg.option('s1.b').option.issymlinkoption()
|
||||||
|
assert cfg.option('c').option.issymlinkoption()
|
||||||
|
assert cfg.option('s1.b').option.type() == _('boolean')
|
||||||
|
assert cfg.option('c').option.type() == _('boolean')
|
||||||
assert cfg.option('s1.b').value.get() is False
|
assert cfg.option('s1.b').value.get() is False
|
||||||
cfg.option("s1.b").value.set(True)
|
cfg.option("s1.b").value.set(True)
|
||||||
cfg.option("s1.b").value.set(False)
|
cfg.option("s1.b").value.set(False)
|
||||||
|
@ -36,6 +42,62 @@ def test_symlink_option(config_type):
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def test_symlink_default(config_type):
|
||||||
|
boolopt = BoolOption("b", "", default=False)
|
||||||
|
linkopt = SymLinkOption("c", boolopt)
|
||||||
|
od1 = OptionDescription("opt", "",
|
||||||
|
[linkopt, OptionDescription("s1", "", [boolopt])],
|
||||||
|
)
|
||||||
|
cfg = Config(od1)
|
||||||
|
cfg = get_config(cfg, config_type)
|
||||||
|
assert not cfg.option('s1.b').option.ismulti()
|
||||||
|
assert not cfg.option('c').option.ismulti()
|
||||||
|
assert not cfg.option('s1.b').option.issubmulti()
|
||||||
|
assert not cfg.option('c').option.issubmulti()
|
||||||
|
assert not cfg.option('s1.b').option.default()
|
||||||
|
assert not cfg.option('c').option.default()
|
||||||
|
assert not cfg.option('s1.b').value.default()
|
||||||
|
assert not cfg.option('c').value.default()
|
||||||
|
with pytest.raises(ConfigError):
|
||||||
|
assert not cfg.option('s1.b').option.defaultmulti()
|
||||||
|
with pytest.raises(ConfigError):
|
||||||
|
assert not cfg.option('c').option.defaultmulti()
|
||||||
|
cfg.option("s1.b").value.set(True)
|
||||||
|
assert not cfg.option('s1.b').option.default()
|
||||||
|
assert not cfg.option('c').option.default()
|
||||||
|
assert not cfg.option('s1.b').value.default()
|
||||||
|
assert not cfg.option('c').value.default()
|
||||||
|
## assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def test_symlink_default_multi(config_type):
|
||||||
|
boolopt = BoolOption("b", "", default=[False], default_multi=True, multi=True)
|
||||||
|
linkopt = SymLinkOption("c", boolopt)
|
||||||
|
od1 = OptionDescription("opt", "",
|
||||||
|
[linkopt, OptionDescription("s1", "", [boolopt])],
|
||||||
|
)
|
||||||
|
cfg = Config(od1)
|
||||||
|
cfg = get_config(cfg, config_type)
|
||||||
|
assert cfg.option('s1.b').option.ismulti()
|
||||||
|
assert cfg.option('c').option.ismulti()
|
||||||
|
assert not cfg.option('s1.b').option.issubmulti()
|
||||||
|
assert not cfg.option('c').option.issubmulti()
|
||||||
|
assert cfg.option('s1.b').option.default() == [False]
|
||||||
|
assert cfg.option('c').option.default() == [False]
|
||||||
|
assert cfg.option('s1.b').value.default() == [False]
|
||||||
|
assert cfg.option('c').value.default() == [False]
|
||||||
|
assert cfg.option('s1.b').option.defaultmulti()
|
||||||
|
assert cfg.option('c').option.defaultmulti()
|
||||||
|
cfg.option("s1.b").value.set([True])
|
||||||
|
assert cfg.option('s1.b').option.default() == [False]
|
||||||
|
assert cfg.option('c').option.default() == [False]
|
||||||
|
assert cfg.option('s1.b').value.default() == [False]
|
||||||
|
assert cfg.option('c').value.default() == [False]
|
||||||
|
assert cfg.option('s1.b').option.defaultmulti()
|
||||||
|
assert cfg.option('c').option.defaultmulti()
|
||||||
|
## assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
def test_symlink_assign_option(config_type):
|
def test_symlink_assign_option(config_type):
|
||||||
boolopt = BoolOption("b", "", default=False)
|
boolopt = BoolOption("b", "", default=False)
|
||||||
linkopt = SymLinkOption("c", boolopt)
|
linkopt = SymLinkOption("c", boolopt)
|
||||||
|
@ -66,14 +128,10 @@ def test_symlink_addproperties():
|
||||||
od1 = OptionDescription('opt', '', [boolopt, linkopt])
|
od1 = OptionDescription('opt', '', [boolopt, linkopt])
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
cfg.property.read_write()
|
cfg.property.read_write()
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(ConfigError):
|
||||||
cfg.option('c').property.add('new')
|
cfg.option('c').property.add('new')
|
||||||
try:
|
with pytest.raises(ConfigError):
|
||||||
cfg.option('c').property.reset()
|
cfg.option('c').property.reset()
|
||||||
except AssertionError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise Exception('must raise')
|
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,14 +152,10 @@ def test_symlink_addpermissives():
|
||||||
od1 = OptionDescription('opt', '', [boolopt, linkopt])
|
od1 = OptionDescription('opt', '', [boolopt, linkopt])
|
||||||
cfg = Config(od1)
|
cfg = Config(od1)
|
||||||
cfg.property.read_write()
|
cfg.property.read_write()
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(ConfigError):
|
||||||
cfg.option('c').permissive.set(frozenset(['new']))
|
cfg.option('c').permissive.set(frozenset(['new']))
|
||||||
try:
|
with pytest.raises(ConfigError):
|
||||||
cfg.option('c').permissive.reset()
|
cfg.option('c').permissive.reset()
|
||||||
except AssertionError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise Exception('must raise')
|
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
@ -340,3 +394,14 @@ def test_symlink_list(config_type):
|
||||||
list_opt.append(opt.option.path())
|
list_opt.append(opt.option.path())
|
||||||
assert list_opt == ['c', 's1.b']
|
assert list_opt == ['c', 's1.b']
|
||||||
# assert not list_sessions()
|
# assert not list_sessions()
|
||||||
|
|
||||||
|
|
||||||
|
def test_submulti():
|
||||||
|
multi = StrOption('multi', '', multi=submulti)
|
||||||
|
multi2 = SymLinkOption('multi2', multi)
|
||||||
|
od1 = OptionDescription('od', '', [multi, multi2])
|
||||||
|
cfg = Config(od1)
|
||||||
|
assert cfg.option('multi').option.ismulti()
|
||||||
|
assert cfg.option('multi').option.issubmulti()
|
||||||
|
assert cfg.option('multi2').option.ismulti()
|
||||||
|
assert cfg.option('multi2').option.issubmulti()
|
||||||
|
|
485
tiramisu/api.py
485
tiramisu/api.py
|
@ -14,20 +14,19 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
from inspect import ismethod, getdoc, signature
|
from inspect import getdoc
|
||||||
from time import time
|
from typing import List, Set, Any, Optional, Callable, Dict
|
||||||
from typing import List, Set, Any, Optional, Callable, Union, Dict
|
|
||||||
from warnings import catch_warnings, simplefilter
|
from warnings import catch_warnings, simplefilter
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
|
|
||||||
from .error import ConfigError, LeadershipError, PropertiesOptionError, ValueErrorWarning
|
from .error import ConfigError, LeadershipError, ValueErrorWarning
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
from .setting import ConfigBag, OptionBag, owners, groups, Undefined, undefined, \
|
from .setting import ConfigBag, OptionBag, owners, groups, undefined, \
|
||||||
FORBIDDEN_SET_PROPERTIES, SPECIAL_PROPERTIES, EXPIRATION_TIME
|
FORBIDDEN_SET_PROPERTIES, SPECIAL_PROPERTIES
|
||||||
from .config import KernelConfig, KernelGroupConfig, KernelMetaConfig, KernelMixConfig
|
from .config import KernelConfig, KernelGroupConfig, KernelMetaConfig, KernelMixConfig
|
||||||
from .option import RegexpOption, OptionDescription
|
from .option import RegexpOption, OptionDescription, ChoiceOption
|
||||||
from .todict import TiramisuDict
|
from .todict import TiramisuDict
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,13 +41,12 @@ class TiramisuHelp:
|
||||||
def display(doc=''):
|
def display(doc=''):
|
||||||
if _display: # pragma: no cover
|
if _display: # pragma: no cover
|
||||||
print(doc)
|
print(doc)
|
||||||
options = []
|
|
||||||
all_modules = dir(self)
|
all_modules = dir(self)
|
||||||
modules = []
|
modules = []
|
||||||
max_len = 0
|
max_len = 0
|
||||||
force = False
|
force = False
|
||||||
for module_name in all_modules:
|
for module_name in all_modules:
|
||||||
if module_name in ['forcepermissive', 'unrestraint']:
|
if module_name in ['forcepermissive', 'unrestraint', 'nowarnings']:
|
||||||
force = True
|
force = True
|
||||||
max_len = max(max_len, len('forcepermissive'))
|
max_len = max(max_len, len('forcepermissive'))
|
||||||
elif module_name != 'help' and not module_name.startswith('_'):
|
elif module_name != 'help' and not module_name.startswith('_'):
|
||||||
|
@ -60,8 +58,16 @@ class TiramisuHelp:
|
||||||
display()
|
display()
|
||||||
if force:
|
if force:
|
||||||
display(_('Settings:'))
|
display(_('Settings:'))
|
||||||
display(self._tmpl_help.format('forcepermissive', _('Access to option without verifying permissive properties')).expandtabs(max_len + 10))
|
display(self._tmpl_help.format('forcepermissive',
|
||||||
display(self._tmpl_help.format('unrestraint', _('Access to option without property restriction')).expandtabs(max_len + 10))
|
_('Access to option without verifying permissive '
|
||||||
|
'properties'),
|
||||||
|
).expandtabs(max_len + 10))
|
||||||
|
display(self._tmpl_help.format('unrestraint',
|
||||||
|
_('Access to option without property restriction')
|
||||||
|
).expandtabs(max_len + 10))
|
||||||
|
display(self._tmpl_help.format('nowarnings',
|
||||||
|
_('Do not warnings during validation')
|
||||||
|
).expandtabs(max_len + 10))
|
||||||
display()
|
display()
|
||||||
if isinstance(self, TiramisuDispatcherOption):
|
if isinstance(self, TiramisuDispatcherOption):
|
||||||
doc = _(getdoc(self.__call__))
|
doc = _(getdoc(self.__call__))
|
||||||
|
@ -81,7 +87,6 @@ class TiramisuHelp:
|
||||||
|
|
||||||
|
|
||||||
class CommonTiramisu(TiramisuHelp):
|
class CommonTiramisu(TiramisuHelp):
|
||||||
_allow_optiondescription = True
|
|
||||||
_validate_properties = True
|
_validate_properties = True
|
||||||
|
|
||||||
def _get_options_bag(self) -> OptionBag:
|
def _get_options_bag(self) -> OptionBag:
|
||||||
|
@ -98,14 +103,6 @@ class CommonTiramisu(TiramisuHelp):
|
||||||
return options_bag
|
return options_bag
|
||||||
|
|
||||||
|
|
||||||
def load_option(func):
|
|
||||||
def wrapped(self, *args, **kwargs):
|
|
||||||
options_bag = self._get_options_bag()
|
|
||||||
return func(self, options_bag, *args, **kwargs)
|
|
||||||
wrapped.func = func
|
|
||||||
return wrapped
|
|
||||||
|
|
||||||
|
|
||||||
def option_type(typ):
|
def option_type(typ):
|
||||||
if not isinstance(typ, list):
|
if not isinstance(typ, list):
|
||||||
types = [typ]
|
types = [typ]
|
||||||
|
@ -115,16 +112,17 @@ def option_type(typ):
|
||||||
def wrapper(func):
|
def wrapper(func):
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def wrapped(*args, **kwargs):
|
def wrapped(*args, **kwargs):
|
||||||
config_bag = args[0]._config_bag
|
self = args[0]
|
||||||
if args[0]._config_bag.context.impl_type == 'group' and 'group' in types:
|
config_bag = self._config_bag
|
||||||
|
if self._config_bag.context.impl_type == 'group' and 'group' in types:
|
||||||
options_bag = [OptionBag(None,
|
options_bag = [OptionBag(None,
|
||||||
None,
|
None,
|
||||||
args[0]._config_bag,
|
self._config_bag,
|
||||||
path=args[0]._path,
|
path=self._path,
|
||||||
)]
|
)]
|
||||||
kwargs['is_group'] = True
|
kwargs['is_group'] = True
|
||||||
return func(args[0], options_bag, *args[1:], **kwargs)
|
return func(self, options_bag, *args[1:], **kwargs)
|
||||||
options_bag = args[0]._get_options_bag()
|
options_bag = self._get_options_bag()
|
||||||
option = options_bag[-1].option
|
option = options_bag[-1].option
|
||||||
if option.impl_is_optiondescription() and 'optiondescription' in types or \
|
if option.impl_is_optiondescription() and 'optiondescription' in types or \
|
||||||
not option.impl_is_optiondescription() and (
|
not option.impl_is_optiondescription() and (
|
||||||
|
@ -133,24 +131,29 @@ def option_type(typ):
|
||||||
'option' in types or \
|
'option' in types or \
|
||||||
option.impl_is_leader() and 'leader' in types or \
|
option.impl_is_leader() and 'leader' in types or \
|
||||||
option.impl_is_follower() and 'follower' in types or \
|
option.impl_is_follower() and 'follower' in types or \
|
||||||
option.get_type() == 'choice' and 'choice' in types)):
|
isinstance(option, ChoiceOption) and 'choice' in types)):
|
||||||
if not option.impl_is_optiondescription() and not option.impl_is_symlinkoption() and option.impl_is_follower():
|
if not option.impl_is_optiondescription() and \
|
||||||
if 'with_index' in types and args[0]._index is not None:
|
not option.impl_is_symlinkoption() and \
|
||||||
raise ConfigError(_(f'please do not specify index ({args[0].__class__.__name__}.{func.__name__})'))
|
option.impl_is_follower():
|
||||||
if 'with_index' not in types and args[0]._index is None:
|
if 'with_index' not in types and 'with_or_without_index' not in types and \
|
||||||
raise ConfigError(_(f'please specify index with a follower option ({args[0].__class__.__name__}.{func.__name__})'))
|
self._index is not None:
|
||||||
elif args[0]._index is not None:
|
msg = _('please do not specify index '
|
||||||
raise ConfigError(_(f'please specify an index only for follower option ({args[0].__class__.__name__}.{func.__name__})'))
|
f'({self.__class__.__name__}.{func.__name__})')
|
||||||
return func(args[0], options_bag, *args[1:], **kwargs)
|
raise ConfigError(_(msg))
|
||||||
raise ConfigError(_(f'please specify a valid sub function ({args[0].__class__.__name__}.{func.__name__})'))
|
if 'with_index' in types and self._index is None:
|
||||||
|
msg = _('please specify index with a follower option '
|
||||||
|
f'({self.__class__.__name__}.{func.__name__})')
|
||||||
|
raise ConfigError(msg)
|
||||||
|
return func(self, options_bag, *args[1:], **kwargs)
|
||||||
|
msg = _('please specify a valid sub function '
|
||||||
|
f'({self.__class__.__name__}.{func.__name__})')
|
||||||
|
raise ConfigError(msg)
|
||||||
wrapped.func = func
|
wrapped.func = func
|
||||||
return wrapped
|
return wrapped
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
class CommonTiramisuOption(CommonTiramisu):
|
class CommonTiramisuOption(CommonTiramisu):
|
||||||
_allow_optiondescription = False
|
|
||||||
_follower_need_index = True
|
|
||||||
_validate_properties = False
|
_validate_properties = False
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
|
@ -167,60 +170,14 @@ class CommonTiramisuOption(CommonTiramisu):
|
||||||
|
|
||||||
|
|
||||||
class _TiramisuOptionWalk:
|
class _TiramisuOptionWalk:
|
||||||
def _filter(self,
|
def _list(self,
|
||||||
opt,
|
root_option_bag,
|
||||||
subconfig,
|
type,
|
||||||
config_bag,
|
|
||||||
):
|
|
||||||
option_bag = OptionBag(opt,
|
|
||||||
None,
|
|
||||||
config_bag,
|
|
||||||
)
|
|
||||||
|
|
||||||
def _walk(self,
|
|
||||||
option,
|
|
||||||
recursive,
|
|
||||||
type_,
|
|
||||||
group_type,
|
group_type,
|
||||||
config_bag,
|
recursive,
|
||||||
subconfig,
|
|
||||||
):
|
):
|
||||||
options = []
|
assert type in ('all', 'option', 'optiondescription'), \
|
||||||
for opt in option.get_children(config_bag):
|
_('unknown list type {}').format(type)
|
||||||
try:
|
|
||||||
#FIXME trop compliqué devrait faire avec get_sub_option_bag ou get_children ne devrait pas lister les variables disables
|
|
||||||
subsubconfig = self._filter(opt,
|
|
||||||
subconfig,
|
|
||||||
config_bag,
|
|
||||||
)
|
|
||||||
except PropertiesOptionError:
|
|
||||||
continue
|
|
||||||
if opt.impl_is_optiondescription():
|
|
||||||
if recursive:
|
|
||||||
options.extend(self._walk(opt,
|
|
||||||
recursive,
|
|
||||||
type_,
|
|
||||||
group_type,
|
|
||||||
config_bag,
|
|
||||||
subsubconfig))
|
|
||||||
if type_ == 'option' or (type_ == 'optiondescription' and \
|
|
||||||
group_type and opt.impl_get_group_type() != group_type):
|
|
||||||
continue
|
|
||||||
elif type_ == 'optiondescription':
|
|
||||||
continue
|
|
||||||
options.append(TiramisuOption(opt.impl_getpath(),
|
|
||||||
None,
|
|
||||||
config_bag,
|
|
||||||
))
|
|
||||||
return options
|
|
||||||
|
|
||||||
def _list2(self,
|
|
||||||
root_option_bag,
|
|
||||||
type,
|
|
||||||
group_type,
|
|
||||||
recursive,
|
|
||||||
):
|
|
||||||
assert type in ('all', 'option', 'optiondescription'), _('unknown list type {}').format(type)
|
|
||||||
assert group_type is None or isinstance(group_type, groups.GroupType), \
|
assert group_type is None or isinstance(group_type, groups.GroupType), \
|
||||||
_("unknown group_type: {0}").format(group_type)
|
_("unknown group_type: {0}").format(group_type)
|
||||||
options = []
|
options = []
|
||||||
|
@ -233,11 +190,18 @@ class _TiramisuOptionWalk:
|
||||||
group_type=group_type,
|
group_type=group_type,
|
||||||
):
|
):
|
||||||
if isinstance(option_bag, dict):
|
if isinstance(option_bag, dict):
|
||||||
for opt_bag in option_bag.values():
|
for opts_bag in option_bag.values():
|
||||||
options.append(TiramisuOption(opt_bag.path,
|
if isinstance(opts_bag, OptionBag):
|
||||||
opt_bag.index,
|
options.append(TiramisuOption(opts_bag.path,
|
||||||
self._config_bag,
|
opts_bag.index,
|
||||||
))
|
self._config_bag,
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
for opt_bag in opts_bag:
|
||||||
|
options.append(TiramisuOption(opt_bag.path,
|
||||||
|
opt_bag.index,
|
||||||
|
self._config_bag,
|
||||||
|
))
|
||||||
else:
|
else:
|
||||||
options.append(TiramisuOption(option_bag.path,
|
options.append(TiramisuOption(option_bag.path,
|
||||||
option_bag.index,
|
option_bag.index,
|
||||||
|
@ -245,82 +209,48 @@ class _TiramisuOptionWalk:
|
||||||
))
|
))
|
||||||
return options
|
return options
|
||||||
|
|
||||||
def _list(self,
|
|
||||||
type,
|
|
||||||
group_type,
|
|
||||||
recursive,
|
|
||||||
root_option,
|
|
||||||
subconfig,
|
|
||||||
config_bag,
|
|
||||||
):
|
|
||||||
assert type in ('all', 'option', 'optiondescription'), _('unknown list type {}').format(type)
|
|
||||||
assert group_type is None or isinstance(group_type, groups.GroupType), \
|
|
||||||
_("unknown group_type: {0}").format(group_type)
|
|
||||||
if config_bag.properties and 'warnings' in config_bag.properties:
|
|
||||||
config_bag = config_bag.copy()
|
|
||||||
config_bag.remove_warnings()
|
|
||||||
options = []
|
|
||||||
for opt in self._walk(root_option,
|
|
||||||
recursive,
|
|
||||||
type,
|
|
||||||
group_type,
|
|
||||||
config_bag,
|
|
||||||
subconfig,
|
|
||||||
):
|
|
||||||
options.append(opt)
|
|
||||||
return options
|
|
||||||
|
|
||||||
|
|
||||||
class _TiramisuOptionOptionDescription(CommonTiramisuOption):
|
class _TiramisuOptionOptionDescription(CommonTiramisuOption):
|
||||||
"""Manage option"""
|
"""Manage option"""
|
||||||
_allow_optiondescription = True
|
|
||||||
_follower_need_index = False
|
|
||||||
_validate_properties = False
|
_validate_properties = False
|
||||||
|
|
||||||
@load_option
|
@option_type(['optiondescription', 'option', 'with_or_without_index'])
|
||||||
def get(self, options_bag: List[OptionBag]):
|
def get(self, options_bag: List[OptionBag]):
|
||||||
"""Get Tiramisu option"""
|
"""Get Tiramisu option"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
return option_bag.option
|
return option_bag.option
|
||||||
|
|
||||||
@load_option
|
@option_type(['optiondescription'])
|
||||||
def isleadership(self, options_bag: List[OptionBag]):
|
def isleadership(self, options_bag: List[OptionBag]):
|
||||||
"""Test if option is a leader or a follower"""
|
"""Test if option is a leader or a follower"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
return option_bag.option.impl_is_leadership()
|
return option_bag.option.impl_is_leadership()
|
||||||
|
|
||||||
@load_option
|
@option_type(['optiondescription', 'option', 'with_or_without_index'])
|
||||||
def doc(self, options_bag: List[OptionBag]):
|
def doc(self, options_bag: List[OptionBag]):
|
||||||
"""Get option document"""
|
"""Get option document"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
return option_bag.option.impl_get_display_name()
|
return option_bag.option.impl_get_display_name()
|
||||||
|
|
||||||
@load_option
|
@option_type(['optiondescription', 'option', 'with_or_without_index'])
|
||||||
def description(self, options_bag: List[OptionBag]):
|
def description(self, options_bag: List[OptionBag]):
|
||||||
"""Get option description"""
|
"""Get option description"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
return option_bag.option.impl_get_information('doc', None)
|
return option_bag.option.impl_get_information('doc', None)
|
||||||
|
|
||||||
@load_option
|
@option_type(['optiondescription', 'option', 'symlink', 'with_or_without_index'])
|
||||||
def name(self,
|
def name(self, options_bag: List[OptionBag]) -> str:
|
||||||
options_bag: List[OptionBag],
|
|
||||||
follow_symlink: bool=False,
|
|
||||||
) -> str:
|
|
||||||
"""Get option name"""
|
"""Get option name"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
if not follow_symlink or \
|
return option_bag.option.impl_getname()
|
||||||
option_bag.option.impl_is_optiondescription() or \
|
|
||||||
not option_bag.option.impl_is_symlinkoption():
|
|
||||||
return option_bag.option.impl_getname()
|
|
||||||
return option_bag.option.impl_getopt().impl_getname()
|
|
||||||
|
|
||||||
@load_option
|
@option_type(['optiondescription', 'option', 'with_or_without_index', 'symlink'])
|
||||||
def path(self, options_bag: List[OptionBag]) -> str:
|
def path(self, options_bag: List[OptionBag]) -> str:
|
||||||
"""Get option path"""
|
"""Get option path"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
return option_bag.path
|
return option_bag.path
|
||||||
|
|
||||||
@load_option
|
@option_type(['optiondescription', 'option', 'symlink'])
|
||||||
def has_dependency(self,
|
def has_dependency(self,
|
||||||
options_bag: List[OptionBag],
|
options_bag: List[OptionBag],
|
||||||
self_is_dep=True,
|
self_is_dep=True,
|
||||||
|
@ -329,7 +259,7 @@ class _TiramisuOptionOptionDescription(CommonTiramisuOption):
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
return option_bag.option.impl_has_dependency(self_is_dep)
|
return option_bag.option.impl_has_dependency(self_is_dep)
|
||||||
|
|
||||||
@load_option
|
@option_type(['optiondescription', 'option'])
|
||||||
def dependencies(self, options_bag: List[OptionBag]):
|
def dependencies(self, options_bag: List[OptionBag]):
|
||||||
"""Get dependencies from this option"""
|
"""Get dependencies from this option"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
|
@ -341,13 +271,13 @@ class _TiramisuOptionOptionDescription(CommonTiramisuOption):
|
||||||
))
|
))
|
||||||
return options
|
return options
|
||||||
|
|
||||||
@load_option
|
@option_type(['optiondescription', 'option', 'with_or_without_index'])
|
||||||
def isoptiondescription(self, options_bag: List[OptionBag]):
|
def isoptiondescription(self, options_bag: List[OptionBag]):
|
||||||
"""Test if option is an optiondescription"""
|
"""Test if option is an optiondescription"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
return option_bag.option.impl_is_optiondescription()
|
return option_bag.option.impl_is_optiondescription()
|
||||||
|
|
||||||
@load_option
|
@option_type(['optiondescription', 'option', 'with_index'])
|
||||||
def properties(self,
|
def properties(self,
|
||||||
options_bag: List[OptionBag],
|
options_bag: List[OptionBag],
|
||||||
only_raises=False,
|
only_raises=False,
|
||||||
|
@ -364,7 +294,6 @@ class _TiramisuOptionOptionDescription(CommonTiramisuOption):
|
||||||
return settings.getproperties(option_bag,
|
return settings.getproperties(option_bag,
|
||||||
apply_requires=False,
|
apply_requires=False,
|
||||||
)
|
)
|
||||||
# do not check cache properties/permissives which are not save (unrestraint, ...)
|
|
||||||
return settings.calc_raises_properties(option_bag,
|
return settings.calc_raises_properties(option_bag,
|
||||||
apply_requires=False,
|
apply_requires=False,
|
||||||
uncalculated=uncalculated,
|
uncalculated=uncalculated,
|
||||||
|
@ -383,55 +312,51 @@ class _TiramisuOptionOptionDescription(CommonTiramisuOption):
|
||||||
|
|
||||||
class TiramisuOptionOption(_TiramisuOptionOptionDescription):
|
class TiramisuOptionOption(_TiramisuOptionOptionDescription):
|
||||||
"""Manage option"""
|
"""Manage option"""
|
||||||
@load_option
|
@option_type(['option', 'symlink', 'with_or_without_index'])
|
||||||
def ismulti(self, options_bag: List[OptionBag]):
|
def ismulti(self, options_bag: List[OptionBag]):
|
||||||
"""Test if option could have multi value"""
|
"""Test if option could have multi value"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
return option_bag.option.impl_is_multi()
|
return option_bag.option.impl_is_multi()
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'symlink', 'with_or_without_index'])
|
||||||
def issubmulti(self, options_bag: List[OptionBag]):
|
def issubmulti(self, options_bag: List[OptionBag]):
|
||||||
"""Test if option could have submulti value"""
|
"""Test if option could have submulti value"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
return option_bag.option.impl_is_submulti()
|
return option_bag.option.impl_is_submulti()
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'with_or_without_index'])
|
||||||
def isleader(self, options_bag: List[OptionBag]):
|
def isleader(self, options_bag: List[OptionBag]):
|
||||||
"""Test if option is a leader"""
|
"""Test if option is a leader"""
|
||||||
option_bag = options_bag[-1]
|
return options_bag[-1].option.impl_is_leader()
|
||||||
return option_bag.option.impl_is_leader()
|
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'with_or_without_index'])
|
||||||
def isfollower(self, options_bag: List[OptionBag]):
|
def isfollower(self, options_bag: List[OptionBag]):
|
||||||
"""Test if option is a follower"""
|
"""Test if option is a follower"""
|
||||||
option_bag = options_bag[-1]
|
return options_bag[-1].option.impl_is_follower()
|
||||||
return option_bag.option.impl_is_follower()
|
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'optiondescription', 'with_or_without_index'])
|
||||||
def isdynamic(self, options_bag: List[OptionBag]):
|
def isdynamic(self, options_bag: List[OptionBag]):
|
||||||
"""Test if option is a dynamic optiondescription"""
|
"""Test if option is a dynamic optiondescription"""
|
||||||
option_bag = options_bag[-1]
|
return options_bag[-1].option.impl_is_dynsymlinkoption()
|
||||||
return option_bag.option.impl_is_dynsymlinkoption()
|
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'symlink', 'with_or_without_index'])
|
||||||
def issymlinkoption(self, options_bag: List[OptionBag]) -> bool:
|
def issymlinkoption(self, options_bag: List[OptionBag]) -> bool:
|
||||||
"""Test if option is a symlink option"""
|
"""Test if option is a symlink option"""
|
||||||
option_bag = options_bag[-1]
|
return options_bag[-1].option.impl_is_symlinkoption()
|
||||||
return option_bag.option.impl_is_symlinkoption()
|
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'with_or_without_index', 'symlink'])
|
||||||
def default(self, options_bag: List[OptionBag]):
|
def default(self, options_bag: List[OptionBag]):
|
||||||
"""Get default value for an option (not for optiondescription)"""
|
"""Get default value for an option (not for optiondescription)"""
|
||||||
option_bag = options_bag[-1]
|
return options_bag[-1].option.impl_getdefault()
|
||||||
return option_bag.option.impl_getdefault()
|
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'with_or_without_index', 'symlink'])
|
||||||
def defaultmulti(self, options_bag: List[OptionBag]):
|
def defaultmulti(self, options_bag: List[OptionBag]):
|
||||||
"""Get default value when added a value for a multi option (not for optiondescription)"""
|
"""Get default value when added a value for a multi option (not for optiondescription)"""
|
||||||
option_bag = options_bag[-1]
|
if not options_bag[-1].option.impl_is_multi():
|
||||||
return option_bag.option.impl_getdefault_multi()
|
raise ConfigError(_('only multi value has defaultmulti'))
|
||||||
|
return options_bag[-1].option.impl_getdefault_multi()
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'optiondescription', 'symlink', 'with_or_without_index'])
|
||||||
def type(self, options_bag: List[OptionBag]):
|
def type(self, options_bag: List[OptionBag]):
|
||||||
"""Get de option type"""
|
"""Get de option type"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
|
@ -439,7 +364,7 @@ class TiramisuOptionOption(_TiramisuOptionOptionDescription):
|
||||||
return 'optiondescription'
|
return 'optiondescription'
|
||||||
return option_bag.option.get_type()
|
return option_bag.option.get_type()
|
||||||
|
|
||||||
@load_option
|
@option_type('option')
|
||||||
def pattern(self, options_bag: List[OptionBag]) -> str:
|
def pattern(self, options_bag: List[OptionBag]) -> str:
|
||||||
"""Get the option pattern"""
|
"""Get the option pattern"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
|
@ -456,15 +381,16 @@ class TiramisuOptionOption(_TiramisuOptionOptionDescription):
|
||||||
#FIXME only from 0.0.0.0 to 255.255.255.255
|
#FIXME only from 0.0.0.0 to 255.255.255.255
|
||||||
return r'^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
|
return r'^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
|
||||||
|
|
||||||
@load_option
|
@option_type('option')
|
||||||
def leader(self, options_bag: List[OptionBag]):
|
def leader(self, options_bag: List[OptionBag]):
|
||||||
"""Get the leader option for a follower option"""
|
"""Get the leader option for a follower option"""
|
||||||
option_bag = options_bag[-1]
|
path = options_bag[-1].option.impl_get_leadership().get_leader().impl_getpath()
|
||||||
return TiramisuOption(option_bag.option.impl_get_leadership().get_leader().impl_getpath(),
|
return TiramisuOption(path,
|
||||||
None,
|
None,
|
||||||
self._config_bag)
|
self._config_bag,
|
||||||
|
)
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'with_or_without_index'])
|
||||||
def index(self, options_bag: List[OptionBag]):
|
def index(self, options_bag: List[OptionBag]):
|
||||||
"""Get then index of option"""
|
"""Get then index of option"""
|
||||||
return options_bag[-1].index
|
return options_bag[-1].index
|
||||||
|
@ -474,7 +400,7 @@ class TiramisuOptionOwner(CommonTiramisuOption):
|
||||||
#FIXME optiondescription must not have Owner!
|
#FIXME optiondescription must not have Owner!
|
||||||
"""Manage option's owner"""
|
"""Manage option's owner"""
|
||||||
|
|
||||||
@option_type(['symlink', 'option'])
|
@option_type(['symlink', 'option', 'with_index'])
|
||||||
def get(self, options_bag: List[OptionBag]):
|
def get(self, options_bag: List[OptionBag]):
|
||||||
"""Get owner for a specified option"""
|
"""Get owner for a specified option"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
|
@ -482,17 +408,15 @@ class TiramisuOptionOwner(CommonTiramisuOption):
|
||||||
parent_option_bag = options_bag[-2]
|
parent_option_bag = options_bag[-2]
|
||||||
else:
|
else:
|
||||||
parent_option_bag = None
|
parent_option_bag = None
|
||||||
return self._config_bag.context.get_owner(option_bag,
|
return self._config_bag.context.get_owner(option_bag)
|
||||||
parent_option_bag,
|
|
||||||
)
|
|
||||||
|
|
||||||
@option_type(['symlink', 'option'])
|
@option_type(['symlink', 'option', 'with_index'])
|
||||||
def isdefault(self, options_bag: List[OptionBag]):
|
def isdefault(self, options_bag: List[OptionBag]):
|
||||||
"""Is option has defaut value"""
|
"""Is option has defaut value"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
return self._config_bag.context.get_values().is_default_owner(option_bag)
|
return self._config_bag.context.get_values().is_default_owner(option_bag)
|
||||||
|
|
||||||
@option_type('option')
|
@option_type(['option', 'with_index'])
|
||||||
def set(self,
|
def set(self,
|
||||||
options_bag: List[OptionBag],
|
options_bag: List[OptionBag],
|
||||||
owner: str,
|
owner: str,
|
||||||
|
@ -511,11 +435,9 @@ class TiramisuOptionOwner(CommonTiramisuOption):
|
||||||
|
|
||||||
class TiramisuOptionProperty(CommonTiramisuOption):
|
class TiramisuOptionProperty(CommonTiramisuOption):
|
||||||
"""Manage option's property"""
|
"""Manage option's property"""
|
||||||
_allow_optiondescription = True
|
|
||||||
_follower_need_index = False
|
|
||||||
_validate_properties = False
|
_validate_properties = False
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'optiondescription', 'with_index'])
|
||||||
def get(self,
|
def get(self,
|
||||||
options_bag: List[OptionBag],
|
options_bag: List[OptionBag],
|
||||||
only_raises=False,
|
only_raises=False,
|
||||||
|
@ -525,14 +447,13 @@ class TiramisuOptionProperty(CommonTiramisuOption):
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
if not only_raises:
|
if not only_raises:
|
||||||
return option_bag.properties
|
return option_bag.properties
|
||||||
# do not check cache properties/permissives which are not save (unrestraint, ...)
|
|
||||||
settings = self._config_bag.context.get_settings()
|
settings = self._config_bag.context.get_settings()
|
||||||
ret = settings.calc_raises_properties(option_bag,
|
ret = settings.calc_raises_properties(option_bag,
|
||||||
uncalculated=uncalculated,
|
uncalculated=uncalculated,
|
||||||
)
|
)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'optiondescription', 'with_or_without_index'])
|
||||||
def add(self,
|
def add(self,
|
||||||
options_bag: List[OptionBag],
|
options_bag: List[OptionBag],
|
||||||
prop,):
|
prop,):
|
||||||
|
@ -542,15 +463,15 @@ class TiramisuOptionProperty(CommonTiramisuOption):
|
||||||
raise ConfigError(_('cannot add this property: "{0}"').format(
|
raise ConfigError(_('cannot add this property: "{0}"').format(
|
||||||
' '.join(prop)))
|
' '.join(prop)))
|
||||||
settings = self._config_bag.context.get_settings()
|
settings = self._config_bag.context.get_settings()
|
||||||
props = settings._getproperties(option_bag.path,
|
props = settings.get_stored_properties(option_bag.path,
|
||||||
option_bag.index,
|
option_bag.index,
|
||||||
option_bag.option.impl_getproperties(),
|
option_bag.option.impl_getproperties(),
|
||||||
)
|
)
|
||||||
settings.setproperties(option_bag,
|
settings.setproperties(option_bag,
|
||||||
props | {prop},
|
props | {prop},
|
||||||
)
|
)
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'optiondescription', 'with_or_without_index'])
|
||||||
def remove(self,
|
def remove(self,
|
||||||
options_bag: List[OptionBag],
|
options_bag: List[OptionBag],
|
||||||
prop,
|
prop,
|
||||||
|
@ -562,7 +483,7 @@ class TiramisuOptionProperty(CommonTiramisuOption):
|
||||||
props - {prop},
|
props - {prop},
|
||||||
)
|
)
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'optiondescription', 'with_or_without_index'])
|
||||||
def reset(self, options_bag: List[OptionBag]):
|
def reset(self, options_bag: List[OptionBag]):
|
||||||
"""Reset all personalised properties"""
|
"""Reset all personalised properties"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
|
@ -571,16 +492,14 @@ class TiramisuOptionProperty(CommonTiramisuOption):
|
||||||
|
|
||||||
class TiramisuOptionPermissive(CommonTiramisuOption):
|
class TiramisuOptionPermissive(CommonTiramisuOption):
|
||||||
"""Manage option's permissive"""
|
"""Manage option's permissive"""
|
||||||
_allow_optiondescription = True
|
|
||||||
_follower_need_index = False
|
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'optiondescription', 'symlink', 'with_index'])
|
||||||
def get(self, options_bag: List[OptionBag]):
|
def get(self, options_bag: List[OptionBag]):
|
||||||
"""Get permissives value"""
|
"""Get permissives value"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
return self._config_bag.context.get_settings().getpermissives(option_bag)
|
return self._config_bag.context.get_settings().getpermissives(option_bag)
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'optiondescription', 'with_or_without_index'])
|
||||||
def set(self,
|
def set(self,
|
||||||
options_bag: List[OptionBag],
|
options_bag: List[OptionBag],
|
||||||
permissives,
|
permissives,
|
||||||
|
@ -591,7 +510,7 @@ class TiramisuOptionPermissive(CommonTiramisuOption):
|
||||||
permissives=permissives,
|
permissives=permissives,
|
||||||
)
|
)
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'optiondescription', 'with_index'])
|
||||||
def reset(self, options_bag: List[OptionBag]):
|
def reset(self, options_bag: List[OptionBag]):
|
||||||
"""Reset all personalised permissive"""
|
"""Reset all personalised permissive"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
|
@ -600,40 +519,36 @@ class TiramisuOptionPermissive(CommonTiramisuOption):
|
||||||
|
|
||||||
class TiramisuOptionInformation(CommonTiramisuOption):
|
class TiramisuOptionInformation(CommonTiramisuOption):
|
||||||
"""Manage option's informations"""
|
"""Manage option's informations"""
|
||||||
_allow_optiondescription = True
|
|
||||||
_follower_need_index = False
|
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'optiondescription', 'with_or_without_index'])
|
||||||
def get(self,
|
def get(self,
|
||||||
options_bag: List[OptionBag],
|
options_bag: List[OptionBag],
|
||||||
key: str,
|
name: str,
|
||||||
default=undefined,
|
default=undefined,
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""Get information"""
|
"""Get information"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
try:
|
try:
|
||||||
return self._config_bag.context.get_values().get_information(self._config_bag,
|
return self._config_bag.context.get_values().get_information(option_bag,
|
||||||
option_bag,
|
name,
|
||||||
key,
|
|
||||||
undefined,
|
undefined,
|
||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return option_bag.option.impl_get_information(key, default)
|
return option_bag.option.impl_get_information(name, default)
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'optiondescription'])
|
||||||
def set(self,
|
def set(self,
|
||||||
options_bag: List[OptionBag],
|
options_bag: List[OptionBag],
|
||||||
key: str,
|
key: str,
|
||||||
value: Any) -> None:
|
value: Any) -> None:
|
||||||
"""Set information"""
|
"""Set information"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
self._config_bag.context.get_values().set_information(self._config_bag,
|
self._config_bag.context.get_values().set_information(option_bag,
|
||||||
option_bag,
|
|
||||||
key,
|
key,
|
||||||
value,
|
value,
|
||||||
)
|
)
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'optiondescription'])
|
||||||
def reset(self,
|
def reset(self,
|
||||||
options_bag: List[OptionBag],
|
options_bag: List[OptionBag],
|
||||||
key: str,
|
key: str,
|
||||||
|
@ -644,7 +559,7 @@ class TiramisuOptionInformation(CommonTiramisuOption):
|
||||||
path=option_bag.path,
|
path=option_bag.path,
|
||||||
)
|
)
|
||||||
|
|
||||||
@load_option
|
@option_type(['option', 'optiondescription', 'with_or_without_index'])
|
||||||
def list(self,
|
def list(self,
|
||||||
options_bag: List[OptionBag],
|
options_bag: List[OptionBag],
|
||||||
) -> list:
|
) -> list:
|
||||||
|
@ -657,19 +572,14 @@ class TiramisuOptionInformation(CommonTiramisuOption):
|
||||||
|
|
||||||
class TiramisuOptionValue(CommonTiramisuOption):
|
class TiramisuOptionValue(CommonTiramisuOption):
|
||||||
"""Manage option's value"""
|
"""Manage option's value"""
|
||||||
_allow_optiondescription = True
|
|
||||||
_follower_need_index = True
|
|
||||||
_validate_properties = True
|
_validate_properties = True
|
||||||
|
|
||||||
@option_type('optiondescription')
|
@option_type('optiondescription')
|
||||||
def dict(self, options_bag: List[OptionBag]):
|
def dict(self, options_bag: List[OptionBag]):
|
||||||
"""Dict with path as key and value"""
|
"""Dict with path as key and value"""
|
||||||
#FIXME : .nowarnings comme .forcepermissive if not withwarning and self._config_bag.properties and 'warnings' in self._config_bag.properties:
|
|
||||||
# option_bag.config_bag = self._config_bag.copy()
|
|
||||||
# option_bag.config_bag.remove_warnings()
|
|
||||||
return self._config_bag.context.make_dict(options_bag[-1])
|
return self._config_bag.context.make_dict(options_bag[-1])
|
||||||
|
|
||||||
@option_type(['option', 'symlink'])
|
@option_type(['option', 'symlink', 'with_index'])
|
||||||
def get(self,
|
def get(self,
|
||||||
options_bag: List[OptionBag],
|
options_bag: List[OptionBag],
|
||||||
):
|
):
|
||||||
|
@ -688,7 +598,7 @@ class TiramisuOptionValue(CommonTiramisuOption):
|
||||||
parent_option_bag,
|
parent_option_bag,
|
||||||
)
|
)
|
||||||
|
|
||||||
@option_type('option')
|
@option_type(['option', 'with_index'])
|
||||||
def set(self,
|
def set(self,
|
||||||
options_bag: List[OptionBag],
|
options_bag: List[OptionBag],
|
||||||
value,
|
value,
|
||||||
|
@ -701,17 +611,18 @@ class TiramisuOptionValue(CommonTiramisuOption):
|
||||||
idx = value.index(undefined)
|
idx = value.index(undefined)
|
||||||
soption_bag = option_bag.copy()
|
soption_bag = option_bag.copy()
|
||||||
soption_bag.index = idx
|
soption_bag.index = idx
|
||||||
value[idx] = values.getdefaultvalue(soption_bag)
|
value[idx] = values.get_default_value(soption_bag)
|
||||||
elif value == undefined:
|
elif value == undefined:
|
||||||
value = values.getdefaultvalue(option_bag)
|
value = values.get_default_value(option_bag)
|
||||||
if option_bag.option.impl_is_leader() and len(value) < self._config_bag.context.get_length_leadership(options_bag[-2]):
|
if option_bag.option.impl_is_leader() and \
|
||||||
|
len(value) < self._config_bag.context.get_length_leadership(options_bag[-2]):
|
||||||
raise LeadershipError(_('cannot reduce length of the leader "{}"'
|
raise LeadershipError(_('cannot reduce length of the leader "{}"'
|
||||||
'').format(option_bag.option.impl_get_display_name()))
|
'').format(option_bag.option.impl_get_display_name()))
|
||||||
return option_bag.config_bag.context.set_value(option_bag,
|
return option_bag.config_bag.context.set_value(option_bag,
|
||||||
value,
|
value,
|
||||||
)
|
)
|
||||||
|
|
||||||
@option_type(['group', 'option'])
|
@option_type(['group', 'option', 'with_index'])
|
||||||
def reset(self,
|
def reset(self,
|
||||||
options_bag: List[OptionBag],
|
options_bag: List[OptionBag],
|
||||||
is_group: bool=False,
|
is_group: bool=False,
|
||||||
|
@ -723,26 +634,18 @@ class TiramisuOptionValue(CommonTiramisuOption):
|
||||||
self._config_bag,
|
self._config_bag,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self._config_bag.context.delattr(option_bag)
|
values = self._config_bag.context.get_values()
|
||||||
|
if option_bag.index is not None:
|
||||||
|
values.reset_follower(option_bag)
|
||||||
|
else:
|
||||||
|
values.reset(option_bag)
|
||||||
|
|
||||||
@option_type('option')
|
@option_type(['option', 'with_index', 'symlink'])
|
||||||
def default(self, options_bag: List[OptionBag]):
|
def default(self, options_bag: List[OptionBag]):
|
||||||
"""Get default value (default of option or calculated value)"""
|
"""Get default value (default of option or calculated value)"""
|
||||||
option_bag = options_bag[-1]
|
return self._config_bag.context.get_values().get_default_value(options_bag[-1])
|
||||||
values = self._config_bag.context.get_values()
|
|
||||||
if option_bag.option.impl_is_symlinkoption():
|
|
||||||
value = []
|
|
||||||
length = self._config_bag.context.get_length_leadership(options_bag[-2])
|
|
||||||
for idx in range(length):
|
|
||||||
soption_bag = OptionBag(options_bag.option,
|
|
||||||
idx,
|
|
||||||
self._config_bag,
|
|
||||||
)
|
|
||||||
value.append(values.getdefaultvalue(soption_bag))
|
|
||||||
return value
|
|
||||||
return values.getdefaultvalue(option_bag)
|
|
||||||
|
|
||||||
@option_type('option')
|
@option_type(['option', 'with_index'])
|
||||||
def valid(self, options_bag: List[OptionBag]):
|
def valid(self, options_bag: List[OptionBag]):
|
||||||
"""The if the option's value is valid"""
|
"""The if the option's value is valid"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
|
@ -757,7 +660,7 @@ class TiramisuOptionValue(CommonTiramisuOption):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@option_type('choice')
|
@option_type(['choice', 'with_index'])
|
||||||
def list(self, options_bag: List[OptionBag]):
|
def list(self, options_bag: List[OptionBag]):
|
||||||
"""All values available for a ChoiceOption"""
|
"""All values available for a ChoiceOption"""
|
||||||
option_bag = options_bag[-1]
|
option_bag = options_bag[-1]
|
||||||
|
@ -766,19 +669,15 @@ class TiramisuOptionValue(CommonTiramisuOption):
|
||||||
@option_type('leader')
|
@option_type('leader')
|
||||||
def pop(self,
|
def pop(self,
|
||||||
options_bag: List[OptionBag],
|
options_bag: List[OptionBag],
|
||||||
index: int):
|
index: int,
|
||||||
|
):
|
||||||
"""Pop a value"""
|
"""Pop a value"""
|
||||||
option_bag = options_bag[-1]
|
self._config_bag.context.get_values().reset_leadership(options_bag[-1],
|
||||||
if len(options_bag) > 1:
|
options_bag[-2],
|
||||||
leadership_option_bag = options_bag[-2]
|
index,
|
||||||
else:
|
)
|
||||||
leadership_option_bag = None
|
|
||||||
self._config_bag.context.pop_leader(option_bag,
|
|
||||||
leadership_option_bag,
|
|
||||||
index,
|
|
||||||
)
|
|
||||||
|
|
||||||
@option_type(['leader', 'follower', 'with_index'])
|
@option_type(['leader', 'follower', 'with_or_without_index'])
|
||||||
def len(self, options_bag: List[OptionBag]):
|
def len(self, options_bag: List[OptionBag]):
|
||||||
"""Length for a follower option"""
|
"""Length for a follower option"""
|
||||||
return self._config_bag.context.get_length_leadership(options_bag[-2])
|
return self._config_bag.context.get_length_leadership(options_bag[-2])
|
||||||
|
@ -786,7 +685,7 @@ class TiramisuOptionValue(CommonTiramisuOption):
|
||||||
|
|
||||||
def _registers(_registers: Dict[str, type],
|
def _registers(_registers: Dict[str, type],
|
||||||
prefix: str,
|
prefix: str,
|
||||||
extra_type: Optional[type]=None):
|
):
|
||||||
for module_name in globals().keys():
|
for module_name in globals().keys():
|
||||||
if module_name != prefix and module_name.startswith(prefix):
|
if module_name != prefix and module_name.startswith(prefix):
|
||||||
module = globals()[module_name]
|
module = globals()[module_name]
|
||||||
|
@ -893,11 +792,11 @@ class TiramisuOption(CommonTiramisu, TiramisuConfig):
|
||||||
group_type=None,
|
group_type=None,
|
||||||
):
|
):
|
||||||
"""List options (by default list only option)"""
|
"""List options (by default list only option)"""
|
||||||
return self._list2(options_bag[-1],
|
return self._list(options_bag[-1],
|
||||||
type,
|
type,
|
||||||
group_type,
|
group_type,
|
||||||
recursive,
|
recursive,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _load_dict(self,
|
def _load_dict(self,
|
||||||
clearable: str="all",
|
clearable: str="all",
|
||||||
|
@ -943,8 +842,7 @@ class TiramisuContextInformation(TiramisuConfig):
|
||||||
"""Get an information"""
|
"""Get an information"""
|
||||||
values = self._config_bag.context.get_values()
|
values = self._config_bag.context.get_values()
|
||||||
try:
|
try:
|
||||||
return values.get_information(self._config_bag,
|
return values.get_information(None,
|
||||||
None,
|
|
||||||
name,
|
name,
|
||||||
undefined,
|
undefined,
|
||||||
)
|
)
|
||||||
|
@ -1115,7 +1013,6 @@ class TiramisuContextProperty(TiramisuConfig):
|
||||||
|
|
||||||
def add(self, prop):
|
def add(self, prop):
|
||||||
"""Add a config property"""
|
"""Add a config property"""
|
||||||
settings = self._config_bag.context.get_settings()
|
|
||||||
props = set(self.get())
|
props = set(self.get())
|
||||||
if prop not in props:
|
if prop not in props:
|
||||||
props.add(prop)
|
props.add(prop)
|
||||||
|
@ -1128,12 +1025,8 @@ class TiramisuContextProperty(TiramisuConfig):
|
||||||
props.remove(prop)
|
props.remove(prop)
|
||||||
self._set(frozenset(props))
|
self._set(frozenset(props))
|
||||||
|
|
||||||
def get(self,
|
def get(self):
|
||||||
default=False):
|
|
||||||
"""Get all config properties"""
|
"""Get all config properties"""
|
||||||
if default:
|
|
||||||
config = self._config_bag.context
|
|
||||||
properties = config.get_settings().get_context_properties(config.properties_cache)
|
|
||||||
return self._config_bag.properties
|
return self._config_bag.properties
|
||||||
|
|
||||||
def _set(self,
|
def _set(self,
|
||||||
|
@ -1168,7 +1061,6 @@ class TiramisuContextProperty(TiramisuConfig):
|
||||||
force_store_value = 'force_store_value' not in self._config_bag.properties
|
force_store_value = 'force_store_value' not in self._config_bag.properties
|
||||||
else:
|
else:
|
||||||
force_store_value = False
|
force_store_value = False
|
||||||
settings = self._config_bag.context.get_settings()
|
|
||||||
self._config_bag.context.get_settings()._properties = deepcopy(properties)
|
self._config_bag.context.get_settings()._properties = deepcopy(properties)
|
||||||
self._config_bag.context.reset_cache(None, None)
|
self._config_bag.context.reset_cache(None, None)
|
||||||
self._reset_config_properties()
|
self._reset_config_properties()
|
||||||
|
@ -1205,8 +1097,9 @@ class TiramisuContextProperty(TiramisuConfig):
|
||||||
raise ValueError(_('unknown type {}').format(type))
|
raise ValueError(_('unknown type {}').format(type))
|
||||||
|
|
||||||
def getdefault(self,
|
def getdefault(self,
|
||||||
type: Optional[str]=None,
|
type: Optional[str]=None,
|
||||||
when: Optional[str]=None) -> Set[str]:
|
when: Optional[str]=None,
|
||||||
|
) -> Set[str]:
|
||||||
setting = self._config_bag.context.get_settings()
|
setting = self._config_bag.context.get_settings()
|
||||||
if type is None and when is None:
|
if type is None and when is None:
|
||||||
return setting.default_properties
|
return setting.default_properties
|
||||||
|
@ -1216,15 +1109,12 @@ class TiramisuContextProperty(TiramisuConfig):
|
||||||
if type == 'read_only':
|
if type == 'read_only':
|
||||||
if when == 'append':
|
if when == 'append':
|
||||||
return setting.ro_append
|
return setting.ro_append
|
||||||
else:
|
return setting.ro_remove
|
||||||
return setting.ro_remove
|
if type == 'read_write':
|
||||||
elif type == 'read_write':
|
|
||||||
if when == 'append':
|
if when == 'append':
|
||||||
return setting.rw_append
|
return setting.rw_append
|
||||||
else:
|
return setting.rw_remove
|
||||||
return setting.rw_remove
|
raise ValueError(_('unknown type {}').format(type))
|
||||||
else:
|
|
||||||
raise ValueError(_('unknown type {}').format(type))
|
|
||||||
|
|
||||||
|
|
||||||
class TiramisuContextPermissive(TiramisuConfig):
|
class TiramisuContextPermissive(TiramisuConfig):
|
||||||
|
@ -1302,7 +1192,8 @@ class TiramisuContextOption(TiramisuConfig, _TiramisuOptionWalk):
|
||||||
):
|
):
|
||||||
option = TiramisuOption(path,
|
option = TiramisuOption(path,
|
||||||
None,
|
None,
|
||||||
self._config_bag)
|
self._config_bag,
|
||||||
|
)
|
||||||
if first:
|
if first:
|
||||||
return option
|
return option
|
||||||
options.append(option)
|
options.append(option)
|
||||||
|
@ -1318,11 +1209,11 @@ class TiramisuContextOption(TiramisuConfig, _TiramisuOptionWalk):
|
||||||
None,
|
None,
|
||||||
self._config_bag,
|
self._config_bag,
|
||||||
)
|
)
|
||||||
return self._list2(root_option_bag,
|
return self._list(root_option_bag,
|
||||||
type,
|
type,
|
||||||
group_type,
|
group_type,
|
||||||
recursive,
|
recursive,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _load_dict(self,
|
def _load_dict(self,
|
||||||
clearable="all",
|
clearable="all",
|
||||||
|
@ -1336,10 +1227,12 @@ class TiramisuContextOption(TiramisuConfig, _TiramisuOptionWalk):
|
||||||
def dict(self,
|
def dict(self,
|
||||||
clearable="all",
|
clearable="all",
|
||||||
remotable="minimum",
|
remotable="minimum",
|
||||||
form=[],
|
form=None,
|
||||||
force=False,
|
force=False,
|
||||||
):
|
):
|
||||||
"""Convert config and option to tiramisu format"""
|
"""Convert config and option to tiramisu format"""
|
||||||
|
if form is None:
|
||||||
|
form = []
|
||||||
if force or self._tiramisu_dict is None:
|
if force or self._tiramisu_dict is None:
|
||||||
self._load_dict(clearable, remotable)
|
self._load_dict(clearable, remotable)
|
||||||
return self._tiramisu_dict.todict(form)
|
return self._tiramisu_dict.todict(form)
|
||||||
|
@ -1356,7 +1249,6 @@ class _TiramisuContextConfigReset():
|
||||||
def reset(self):
|
def reset(self):
|
||||||
"""Remove all datas to current config (informations, values, properties, ...)"""
|
"""Remove all datas to current config (informations, values, properties, ...)"""
|
||||||
# Option's values
|
# Option's values
|
||||||
settings = self._config_bag.context.get_settings()
|
|
||||||
context_owner = self._config_bag.context.get_values().get_context_owner()
|
context_owner = self._config_bag.context.get_values().get_context_owner()
|
||||||
self._config_bag.context.get_values()._values = {None: {None: [None, context_owner]}}
|
self._config_bag.context.get_values()._values = {None: {None: [None, context_owner]}}
|
||||||
# Option's informations
|
# Option's informations
|
||||||
|
@ -1470,6 +1362,7 @@ class _TiramisuContextMixConfig(_TiramisuContextGroupConfig, _TiramisuContextCon
|
||||||
def add(self,
|
def add(self,
|
||||||
config):
|
config):
|
||||||
"""Add config from MetaConfig"""
|
"""Add config from MetaConfig"""
|
||||||
|
# pylint: disable=protected-access
|
||||||
self._config_bag.context.add_config(config._config_bag.context)
|
self._config_bag.context.add_config(config._config_bag.context)
|
||||||
|
|
||||||
def parents(self):
|
def parents(self):
|
||||||
|
@ -1495,7 +1388,8 @@ class TiramisuContextCache(TiramisuConfig):
|
||||||
self._config_bag.context.reset_cache(None, None)
|
self._config_bag.context.reset_cache(None, None)
|
||||||
|
|
||||||
def set_expiration_time(self,
|
def set_expiration_time(self,
|
||||||
time: int) -> None:
|
time: int,
|
||||||
|
) -> None:
|
||||||
"""Change expiration time value"""
|
"""Change expiration time value"""
|
||||||
self._config_bag.expiration_time = time
|
self._config_bag.expiration_time = time
|
||||||
|
|
||||||
|
@ -1505,6 +1399,8 @@ class TiramisuContextCache(TiramisuConfig):
|
||||||
|
|
||||||
|
|
||||||
class TiramisuAPI(TiramisuHelp):
|
class TiramisuAPI(TiramisuHelp):
|
||||||
|
"""TiramisuAPI common class
|
||||||
|
"""
|
||||||
_registers = {}
|
_registers = {}
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
|
@ -1520,16 +1416,19 @@ class TiramisuAPI(TiramisuHelp):
|
||||||
config_bag = self._config_bag
|
config_bag = self._config_bag
|
||||||
return TiramisuDispatcherOption(config_bag,
|
return TiramisuDispatcherOption(config_bag,
|
||||||
self._orig_config_bags)
|
self._orig_config_bags)
|
||||||
elif subfunc in ['forcepermissive', 'unrestraint']:
|
if subfunc in ['forcepermissive', 'unrestraint', 'nowarnings']:
|
||||||
if self._orig_config_bags:
|
if self._orig_config_bags:
|
||||||
raise ConfigError(_('do not use unrestraint and forcepermissive together'))
|
msg = _('do not use unrestraint, nowarnings or forcepermissive together')
|
||||||
|
raise ConfigError(msg)
|
||||||
config_bag = self._config_bag.copy()
|
config_bag = self._config_bag.copy()
|
||||||
if subfunc == 'unrestraint':
|
if subfunc == 'unrestraint':
|
||||||
config_bag.unrestraint()
|
config_bag.unrestraint()
|
||||||
|
elif subfunc == 'nowarnings':
|
||||||
|
config_bag.nowarnings()
|
||||||
else:
|
else:
|
||||||
config_bag.set_permissive()
|
config_bag.set_permissive()
|
||||||
return TiramisuAPI(config_bag, [self._config_bag])
|
return TiramisuAPI(config_bag, [self._config_bag])
|
||||||
elif subfunc == 'config':
|
if subfunc == 'config':
|
||||||
config_type = self._config_bag.context.impl_type
|
config_type = self._config_bag.context.impl_type
|
||||||
if config_type == 'group':
|
if config_type == 'group':
|
||||||
config = _TiramisuContextGroupConfig
|
config = _TiramisuContextGroupConfig
|
||||||
|
@ -1541,7 +1440,7 @@ class TiramisuAPI(TiramisuHelp):
|
||||||
config = _TiramisuContextConfig
|
config = _TiramisuContextConfig
|
||||||
return config(self._config_bag,
|
return config(self._config_bag,
|
||||||
self._orig_config_bags)
|
self._orig_config_bags)
|
||||||
elif subfunc in self._registers:
|
if subfunc in self._registers:
|
||||||
config_bag = self._config_bag
|
config_bag = self._config_bag
|
||||||
# del config_bag.permissives
|
# del config_bag.permissives
|
||||||
return self._registers[subfunc](config_bag,
|
return self._registers[subfunc](config_bag,
|
||||||
|
@ -1549,18 +1448,21 @@ class TiramisuAPI(TiramisuHelp):
|
||||||
raise ConfigError(_('please specify a valid sub function ({})').format(subfunc))
|
raise ConfigError(_('please specify a valid sub function ({})').format(subfunc))
|
||||||
|
|
||||||
def __dir__(self):
|
def __dir__(self):
|
||||||
return list(self._registers.keys()) + ['unrestraint', 'forcepermissive', 'config']
|
return list(self._registers.keys()) + \
|
||||||
|
['unrestraint', 'forcepermissive', 'nowarnings', 'config']
|
||||||
|
|
||||||
|
|
||||||
class TiramisuDispatcherOption(TiramisuContextOption):
|
class TiramisuDispatcherOption(TiramisuContextOption):
|
||||||
"""Select an option"""
|
"""Select an option"""
|
||||||
def __call__(self,
|
def __call__(self,
|
||||||
path: str,
|
path: str,
|
||||||
index: Optional[int]=None) -> TiramisuOption:
|
index: Optional[int]=None,
|
||||||
|
) -> TiramisuOption:
|
||||||
"""Select an option by path"""
|
"""Select an option by path"""
|
||||||
return TiramisuOption(path,
|
return TiramisuOption(path,
|
||||||
index,
|
index,
|
||||||
self._config_bag)
|
self._config_bag,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Config(TiramisuAPI):
|
class Config(TiramisuAPI):
|
||||||
|
@ -1591,18 +1493,23 @@ class Config(TiramisuAPI):
|
||||||
del self._config_bag.context
|
del self._config_bag.context
|
||||||
del self._config_bag
|
del self._config_bag
|
||||||
del self._orig_config_bags
|
del self._orig_config_bags
|
||||||
except:
|
except ConfigError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class MetaConfig(TiramisuAPI):
|
class MetaConfig(TiramisuAPI):
|
||||||
"""MetaConfig object that enables us to handle the sub configuration's options with common root optiondescription"""
|
"""MetaConfig object that enables us to handle the sub configuration's options
|
||||||
|
with common root optiondescription
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
children: 'Config'=[],
|
children: 'Config'=None,
|
||||||
name=None,
|
name=None,
|
||||||
optiondescription: Optional[OptionDescription]=None,
|
optiondescription: Optional[OptionDescription]=None,
|
||||||
display_name=None
|
display_name=None
|
||||||
) -> None:
|
) -> None:
|
||||||
|
if children is None:
|
||||||
|
children = []
|
||||||
if isinstance(children, KernelMetaConfig):
|
if isinstance(children, KernelMetaConfig):
|
||||||
config = children
|
config = children
|
||||||
else:
|
else:
|
||||||
|
@ -1628,7 +1535,10 @@ class MetaConfig(TiramisuAPI):
|
||||||
|
|
||||||
|
|
||||||
class MixConfig(TiramisuAPI):
|
class MixConfig(TiramisuAPI):
|
||||||
"""MixConfig object that enables us to handle the sub configuration's options with differents root optiondescription"""
|
"""MixConfig object that enables us to handle the sub configuration's options
|
||||||
|
with differents root optiondescription
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
optiondescription: OptionDescription,
|
optiondescription: OptionDescription,
|
||||||
children: List[Config],
|
children: List[Config],
|
||||||
|
@ -1661,6 +1571,7 @@ class MixConfig(TiramisuAPI):
|
||||||
|
|
||||||
class GroupConfig(TiramisuAPI):
|
class GroupConfig(TiramisuAPI):
|
||||||
"""GroupConfig that enables us to access the sub configuration's options"""
|
"""GroupConfig that enables us to access the sub configuration's options"""
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
children,
|
children,
|
||||||
name=None,
|
name=None,
|
||||||
|
|
|
@ -24,6 +24,7 @@ from itertools import chain
|
||||||
from .error import PropertiesOptionError, ConfigError, LeadershipError, ValueWarning
|
from .error import PropertiesOptionError, ConfigError, LeadershipError, ValueWarning
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
from .setting import undefined, ConfigBag, OptionBag, Undefined
|
from .setting import undefined, ConfigBag, OptionBag, Undefined
|
||||||
|
from .function import FUNCTION_WAITING_FOR_DICT
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,15 +59,15 @@ class Param:
|
||||||
|
|
||||||
|
|
||||||
class ParamOption(Param):
|
class ParamOption(Param):
|
||||||
__slots__ = ('todict',
|
__slots__ = ('option',
|
||||||
'option',
|
|
||||||
'notraisepropertyerror',
|
'notraisepropertyerror',
|
||||||
'raisepropertyerror')
|
'raisepropertyerror',
|
||||||
|
)
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
option: 'Option',
|
option: 'Option',
|
||||||
notraisepropertyerror: bool=False,
|
notraisepropertyerror: bool=False,
|
||||||
raisepropertyerror: bool=False,
|
raisepropertyerror: bool=False,
|
||||||
todict: bool=False) -> None:
|
) -> None:
|
||||||
if __debug__ and not hasattr(option, 'impl_is_symlinkoption'):
|
if __debug__ and not hasattr(option, 'impl_is_symlinkoption'):
|
||||||
raise ValueError(_('paramoption needs an option not {}').format(type(option)))
|
raise ValueError(_('paramoption needs an option not {}').format(type(option)))
|
||||||
if option.impl_is_symlinkoption():
|
if option.impl_is_symlinkoption():
|
||||||
|
@ -75,7 +76,6 @@ class ParamOption(Param):
|
||||||
cur_opt = option
|
cur_opt = option
|
||||||
assert isinstance(notraisepropertyerror, bool), _('param must have a boolean not a {} for notraisepropertyerror').format(type(notraisepropertyerror))
|
assert isinstance(notraisepropertyerror, bool), _('param must have a boolean not a {} for notraisepropertyerror').format(type(notraisepropertyerror))
|
||||||
assert isinstance(raisepropertyerror, bool), _('param must have a boolean not a {} for raisepropertyerror').format(type(raisepropertyerror))
|
assert isinstance(raisepropertyerror, bool), _('param must have a boolean not a {} for raisepropertyerror').format(type(raisepropertyerror))
|
||||||
self.todict = todict
|
|
||||||
self.option = cur_opt
|
self.option = cur_opt
|
||||||
self.notraisepropertyerror = notraisepropertyerror
|
self.notraisepropertyerror = notraisepropertyerror
|
||||||
self.raisepropertyerror = raisepropertyerror
|
self.raisepropertyerror = raisepropertyerror
|
||||||
|
@ -90,12 +90,10 @@ class ParamDynOption(ParamOption):
|
||||||
notraisepropertyerror: bool=False,
|
notraisepropertyerror: bool=False,
|
||||||
raisepropertyerror: bool=False,
|
raisepropertyerror: bool=False,
|
||||||
optional: bool=False,
|
optional: bool=False,
|
||||||
todict: bool=False,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(option,
|
super().__init__(option,
|
||||||
notraisepropertyerror,
|
notraisepropertyerror,
|
||||||
raisepropertyerror,
|
raisepropertyerror,
|
||||||
todict,
|
|
||||||
)
|
)
|
||||||
self.suffix = suffix
|
self.suffix = suffix
|
||||||
self.dynoptiondescription = dynoptiondescription
|
self.dynoptiondescription = dynoptiondescription
|
||||||
|
@ -103,12 +101,11 @@ class ParamDynOption(ParamOption):
|
||||||
|
|
||||||
|
|
||||||
class ParamSelfOption(Param):
|
class ParamSelfOption(Param):
|
||||||
__slots__ = ('todict', 'whole')
|
__slots__ = ('whole')
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
todict: bool=False,
|
whole: bool=undefined,
|
||||||
whole: bool=undefined) -> None:
|
) -> None:
|
||||||
"""whole: send all value for a multi, not only indexed value"""
|
"""whole: send all value for a multi, not only indexed value"""
|
||||||
self.todict = todict
|
|
||||||
if whole is not undefined:
|
if whole is not undefined:
|
||||||
self.whole = whole
|
self.whole = whole
|
||||||
|
|
||||||
|
@ -206,23 +203,13 @@ class Calculation:
|
||||||
for_settings=for_settings,
|
for_settings=for_settings,
|
||||||
)
|
)
|
||||||
|
|
||||||
def has_index(self, current_option):
|
|
||||||
if hasattr(self, '_has_index'):
|
|
||||||
return self._has_index
|
|
||||||
self._has_index = False
|
|
||||||
for arg in chain(self.params.args, self.params.kwargs.values()):
|
|
||||||
if isinstance(arg, ParamOption) and arg.option.impl_get_leadership() and \
|
|
||||||
arg.option.impl_get_leadership().in_same_group(current_option):
|
|
||||||
self._has_index = True
|
|
||||||
break
|
|
||||||
return self._has_index
|
|
||||||
|
|
||||||
|
|
||||||
class Break(Exception):
|
class Break(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def manager_callback(callbk: Param,
|
def manager_callback(callback: Callable,
|
||||||
|
param: Param,
|
||||||
option,
|
option,
|
||||||
index: Optional[int],
|
index: Optional[int],
|
||||||
orig_value,
|
orig_value,
|
||||||
|
@ -231,10 +218,10 @@ def manager_callback(callbk: Param,
|
||||||
for_settings: bool,
|
for_settings: bool,
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""replace Param by true value"""
|
"""replace Param by true value"""
|
||||||
def calc_index(callbk, index, same_leadership):
|
def calc_index(param, index, same_leadership):
|
||||||
if index is not None:
|
if index is not None:
|
||||||
if hasattr(callbk, 'whole'):
|
if hasattr(param, 'whole'):
|
||||||
whole = callbk.whole
|
whole = param.whole
|
||||||
else:
|
else:
|
||||||
# if value is same_leadership, follower are isolate by default
|
# if value is same_leadership, follower are isolate by default
|
||||||
# otherwise option is a whole option
|
# otherwise option is a whole option
|
||||||
|
@ -243,7 +230,7 @@ def manager_callback(callbk: Param,
|
||||||
return index
|
return index
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def calc_self(callbk,
|
def calc_self(param,
|
||||||
option,
|
option,
|
||||||
index,
|
index,
|
||||||
value,
|
value,
|
||||||
|
@ -251,10 +238,8 @@ def manager_callback(callbk: Param,
|
||||||
):
|
):
|
||||||
# index must be apply only if follower
|
# index must be apply only if follower
|
||||||
is_follower = option.impl_is_follower()
|
is_follower = option.impl_is_follower()
|
||||||
apply_index = calc_index(callbk, index, is_follower)
|
apply_index = calc_index(param, index, is_follower)
|
||||||
if value is undefined or (apply_index is None and is_follower):
|
if value is undefined or (apply_index is None and is_follower):
|
||||||
if config_bag is undefined:
|
|
||||||
return undefined
|
|
||||||
path = option.impl_getpath()
|
path = option.impl_getpath()
|
||||||
option_bag = OptionBag(option,
|
option_bag = OptionBag(option,
|
||||||
None,
|
None,
|
||||||
|
@ -266,7 +251,7 @@ def manager_callback(callbk: Param,
|
||||||
)
|
)
|
||||||
parent_option_bag, option_bag = get_option_bag(config_bag,
|
parent_option_bag, option_bag = get_option_bag(config_bag,
|
||||||
option,
|
option,
|
||||||
callbk,
|
param,
|
||||||
apply_index,
|
apply_index,
|
||||||
True,
|
True,
|
||||||
properties=properties,
|
properties=properties,
|
||||||
|
@ -276,17 +261,17 @@ def manager_callback(callbk: Param,
|
||||||
for idx in range(config_bag.context.get_length_leadership(parent_option_bag)):
|
for idx in range(config_bag.context.get_length_leadership(parent_option_bag)):
|
||||||
parent_option_bag, option_bag = get_option_bag(config_bag,
|
parent_option_bag, option_bag = get_option_bag(config_bag,
|
||||||
option,
|
option,
|
||||||
callbk,
|
param,
|
||||||
idx,
|
idx,
|
||||||
True,
|
True,
|
||||||
properties=properties,
|
properties=properties,
|
||||||
)
|
)
|
||||||
new_value.append(get_value(callbk,
|
new_value.append(get_value(param,
|
||||||
option_bag,
|
option_bag,
|
||||||
path,
|
path,
|
||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
new_value = get_value(callbk,
|
new_value = get_value(param,
|
||||||
option_bag,
|
option_bag,
|
||||||
path,
|
path,
|
||||||
)
|
)
|
||||||
|
@ -297,7 +282,7 @@ def manager_callback(callbk: Param,
|
||||||
value = value[apply_index]
|
value = value[apply_index]
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def get_value(callbk,
|
def get_value(param,
|
||||||
option_bag,
|
option_bag,
|
||||||
path,
|
path,
|
||||||
):
|
):
|
||||||
|
@ -306,14 +291,14 @@ def manager_callback(callbk: Param,
|
||||||
value = config_bag.context.get_value(option_bag)
|
value = config_bag.context.get_value(option_bag)
|
||||||
except PropertiesOptionError as err:
|
except PropertiesOptionError as err:
|
||||||
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
|
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
|
||||||
if callbk.notraisepropertyerror or callbk.raisepropertyerror:
|
if param.notraisepropertyerror or param.raisepropertyerror:
|
||||||
raise err from err
|
raise err from err
|
||||||
raise ConfigError(_('unable to carry out a calculation for "{}"'
|
raise ConfigError(_('unable to carry out a calculation for "{}"'
|
||||||
', {}').format(option.impl_get_display_name(), err), err) from err
|
', {}').format(option.impl_get_display_name(), err), err) from err
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(option_bag.option.impl_get_display_name(), err)) from err
|
raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(option_bag.option.impl_get_display_name(), err)) from err
|
||||||
except AttributeError as err:
|
except AttributeError as err:
|
||||||
if isinstance(callbk, ParamDynOption) and callbk.optional:
|
if isinstance(param, ParamDynOption) and param.optional:
|
||||||
# cannot acces, simulate a propertyerror
|
# cannot acces, simulate a propertyerror
|
||||||
raise PropertiesOptionError(option_bag,
|
raise PropertiesOptionError(option_bag,
|
||||||
['configerror'],
|
['configerror'],
|
||||||
|
@ -324,7 +309,7 @@ def manager_callback(callbk: Param,
|
||||||
|
|
||||||
def get_option_bag(config_bag,
|
def get_option_bag(config_bag,
|
||||||
opt,
|
opt,
|
||||||
callbk,
|
param,
|
||||||
index_,
|
index_,
|
||||||
self_calc,
|
self_calc,
|
||||||
properties=undefined,
|
properties=undefined,
|
||||||
|
@ -352,14 +337,14 @@ def manager_callback(callbk: Param,
|
||||||
)
|
)
|
||||||
except PropertiesOptionError as err:
|
except PropertiesOptionError as err:
|
||||||
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
|
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
|
||||||
if callbk.notraisepropertyerror or callbk.raisepropertyerror:
|
if param.notraisepropertyerror or param.raisepropertyerror:
|
||||||
raise err from err
|
raise err from err
|
||||||
raise ConfigError(_('unable to carry out a calculation for "{}"'
|
raise ConfigError(_('unable to carry out a calculation for "{}"'
|
||||||
', {}').format(option.impl_get_display_name(), err), err) from err
|
', {}').format(option.impl_get_display_name(), err), err) from err
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(option.impl_get_display_name(), err)) from err
|
raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(option.impl_get_display_name(), err)) from err
|
||||||
except AttributeError as err:
|
except AttributeError as err:
|
||||||
if isinstance(callbk, ParamDynOption) and callbk.optional:
|
if isinstance(param, ParamDynOption) and param.optional:
|
||||||
# cannot acces, simulate a propertyerror
|
# cannot acces, simulate a propertyerror
|
||||||
raise PropertiesOptionError(options_bag[-1],
|
raise PropertiesOptionError(options_bag[-1],
|
||||||
['configerror'],
|
['configerror'],
|
||||||
|
@ -375,11 +360,11 @@ def manager_callback(callbk: Param,
|
||||||
else:
|
else:
|
||||||
return options_bag[-1]
|
return options_bag[-1]
|
||||||
|
|
||||||
if isinstance(callbk, ParamValue):
|
if isinstance(param, ParamValue):
|
||||||
return callbk.value
|
return param.value
|
||||||
|
|
||||||
if isinstance(callbk, ParamInformation):
|
if isinstance(param, ParamInformation):
|
||||||
if isinstance(callbk, ParamSelfInformation):
|
if isinstance(param, ParamSelfInformation):
|
||||||
option_bag = OptionBag(option,
|
option_bag = OptionBag(option,
|
||||||
index,
|
index,
|
||||||
config_bag,
|
config_bag,
|
||||||
|
@ -387,48 +372,47 @@ def manager_callback(callbk: Param,
|
||||||
else:
|
else:
|
||||||
option_bag = None
|
option_bag = None
|
||||||
try:
|
try:
|
||||||
return config_bag.context.impl_get_information(config_bag,
|
return config_bag.context.impl_get_information(option_bag,
|
||||||
option_bag,
|
param.information_name,
|
||||||
callbk.information_name,
|
param.default_value,
|
||||||
callbk.default_value,
|
|
||||||
)
|
)
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
raise ConfigError(_('option "{}" cannot be calculated: {}').format(option.impl_get_display_name(),
|
raise ConfigError(_('option "{}" cannot be calculated: {}').format(option.impl_get_display_name(),
|
||||||
str(err),
|
str(err),
|
||||||
))
|
))
|
||||||
|
|
||||||
if isinstance(callbk, ParamIndex):
|
if isinstance(param, ParamIndex):
|
||||||
return index
|
return index
|
||||||
|
|
||||||
if isinstance(callbk, ParamSuffix):
|
if isinstance(param, ParamSuffix):
|
||||||
if not option.issubdyn():
|
if not option.issubdyn():
|
||||||
raise ConfigError(_('option "{}" is not in a dynoptiondescription').format(option.impl_get_display_name()))
|
raise ConfigError(_('option "{}" is not in a dynoptiondescription').format(option.impl_get_display_name()))
|
||||||
return option.impl_getsuffix()
|
return option.impl_getsuffix()
|
||||||
|
|
||||||
if isinstance(callbk, ParamSelfOption):
|
if isinstance(param, ParamSelfOption):
|
||||||
if leadership_must_have_index and option.impl_is_follower() and index is None:
|
if leadership_must_have_index and option.impl_is_follower() and index is None:
|
||||||
raise Break()
|
raise Break()
|
||||||
value = calc_self(callbk,
|
value = calc_self(param,
|
||||||
option,
|
option,
|
||||||
index,
|
index,
|
||||||
orig_value,
|
orig_value,
|
||||||
config_bag,
|
config_bag,
|
||||||
)
|
)
|
||||||
if not callbk.todict:
|
if callback.__name__ not in FUNCTION_WAITING_FOR_DICT:
|
||||||
return value
|
return value
|
||||||
return {'name': option.impl_get_display_name(),
|
return {'name': option.impl_get_display_name(),
|
||||||
'value': value,
|
'value': value,
|
||||||
}
|
}
|
||||||
|
|
||||||
if isinstance(callbk, ParamOption):
|
if isinstance(param, ParamOption):
|
||||||
callbk_option = callbk.option
|
callbk_option = param.option
|
||||||
callbk_options = None
|
callbk_options = None
|
||||||
if callbk_option.issubdyn():
|
if callbk_option.issubdyn():
|
||||||
found = False
|
found = False
|
||||||
if isinstance(callbk, ParamDynOption):
|
if isinstance(param, ParamDynOption):
|
||||||
subdyn = callbk.dynoptiondescription
|
subdyn = param.dynoptiondescription
|
||||||
rootpath = subdyn.impl_getpath() + callbk.suffix
|
rootpath = subdyn.impl_getpath() + param.suffix
|
||||||
suffix = callbk.suffix
|
suffix = param.suffix
|
||||||
callbk_option = callbk_option.to_dynoption(rootpath,
|
callbk_option = callbk_option.to_dynoption(rootpath,
|
||||||
suffix,
|
suffix,
|
||||||
subdyn,
|
subdyn,
|
||||||
|
@ -462,8 +446,6 @@ def manager_callback(callbk: Param,
|
||||||
callbk_options.append(doption)
|
callbk_options.append(doption)
|
||||||
if leadership_must_have_index and callbk_option.impl_is_follower() and index is None:
|
if leadership_must_have_index and callbk_option.impl_is_follower() and index is None:
|
||||||
raise Break()
|
raise Break()
|
||||||
if config_bag is undefined:
|
|
||||||
return undefined
|
|
||||||
if callbk_options is None:
|
if callbk_options is None:
|
||||||
callbk_options = [callbk_option]
|
callbk_options = [callbk_option]
|
||||||
values = None
|
values = None
|
||||||
|
@ -471,7 +453,7 @@ def manager_callback(callbk: Param,
|
||||||
values = []
|
values = []
|
||||||
for callbk_option in callbk_options:
|
for callbk_option in callbk_options:
|
||||||
if index is not None and callbk_option.impl_get_leadership() and \
|
if index is not None and callbk_option.impl_get_leadership() and \
|
||||||
callbk_option.impl_get_leadership().in_same_group(option):
|
callbk_option.impl_get_leadership().in_same_leadership(option):
|
||||||
if not callbk_option.impl_is_follower():
|
if not callbk_option.impl_is_follower():
|
||||||
# leader
|
# leader
|
||||||
index_ = None
|
index_ = None
|
||||||
|
@ -486,11 +468,11 @@ def manager_callback(callbk: Param,
|
||||||
path = callbk_option.impl_getpath()
|
path = callbk_option.impl_getpath()
|
||||||
option_bag = get_option_bag(config_bag,
|
option_bag = get_option_bag(config_bag,
|
||||||
callbk_option,
|
callbk_option,
|
||||||
callbk,
|
param,
|
||||||
index_,
|
index_,
|
||||||
False,
|
False,
|
||||||
)
|
)
|
||||||
value = get_value(callbk,
|
value = get_value(param,
|
||||||
option_bag,
|
option_bag,
|
||||||
path,
|
path,
|
||||||
)
|
)
|
||||||
|
@ -500,12 +482,10 @@ def manager_callback(callbk: Param,
|
||||||
values.append(value)
|
values.append(value)
|
||||||
if values is not None:
|
if values is not None:
|
||||||
value = values
|
value = values
|
||||||
if not callbk.todict:
|
if callback.__name__ not in FUNCTION_WAITING_FOR_DICT:
|
||||||
return value
|
return value
|
||||||
return {'name': callbk_option.impl_get_display_name(),
|
return {'name': callbk_option.impl_get_display_name(),
|
||||||
'value': value}
|
'value': value}
|
||||||
raise ConfigError(_('unknown callback type {} in option {}').format(callbk,
|
|
||||||
option.impl_get_display_name()))
|
|
||||||
|
|
||||||
|
|
||||||
def carry_out_calculation(option,
|
def carry_out_calculation(option,
|
||||||
|
@ -540,9 +520,10 @@ def carry_out_calculation(option,
|
||||||
args = []
|
args = []
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
if callback_params:
|
if callback_params:
|
||||||
for key, callbk in chain(fake_items(callback_params.args), callback_params.kwargs.items()):
|
for key, param in chain(fake_items(callback_params.args), callback_params.kwargs.items()):
|
||||||
try:
|
try:
|
||||||
value = manager_callback(callbk,
|
value = manager_callback(callback,
|
||||||
|
param,
|
||||||
option,
|
option,
|
||||||
index,
|
index,
|
||||||
orig_value,
|
orig_value,
|
||||||
|
@ -550,16 +531,14 @@ def carry_out_calculation(option,
|
||||||
leadership_must_have_index,
|
leadership_must_have_index,
|
||||||
for_settings,
|
for_settings,
|
||||||
)
|
)
|
||||||
if value is undefined:
|
|
||||||
return undefined
|
|
||||||
if key is None:
|
if key is None:
|
||||||
args.append(value)
|
args.append(value)
|
||||||
else:
|
else:
|
||||||
kwargs[key] = value
|
kwargs[key] = value
|
||||||
except PropertiesOptionError as err:
|
except PropertiesOptionError as err:
|
||||||
if callbk.raisepropertyerror:
|
if param.raisepropertyerror:
|
||||||
raise err
|
raise err
|
||||||
if callbk.todict:
|
if callback.__name__ in FUNCTION_WAITING_FOR_DICT:
|
||||||
if key is None:
|
if key is None:
|
||||||
args.append({'propertyerror': str(err)})
|
args.append({'propertyerror': str(err)})
|
||||||
else:
|
else:
|
||||||
|
@ -616,8 +595,6 @@ def calculate(option,
|
||||||
raise err
|
raise err
|
||||||
error = err
|
error = err
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
# import traceback
|
|
||||||
# traceback.print_exc()
|
|
||||||
error = err
|
error = err
|
||||||
if args or kwargs:
|
if args or kwargs:
|
||||||
msg = _('unexpected error "{0}" in function "{1}" with arguments "{3}" and "{4}" '
|
msg = _('unexpected error "{0}" in function "{1}" with arguments "{3}" and "{4}" '
|
||||||
|
|
|
@ -16,79 +16,91 @@
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
from time import time
|
from time import time
|
||||||
from .log import log
|
|
||||||
|
|
||||||
|
|
||||||
def _display_classname(obj): # pragma: no cover
|
|
||||||
return(obj.__class__.__name__.lower())
|
|
||||||
|
|
||||||
|
|
||||||
class Cache:
|
class Cache:
|
||||||
|
"""cache object
|
||||||
|
"""
|
||||||
__slots__ = ('_cache',)
|
__slots__ = ('_cache',)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._cache = {}
|
self._cache = {}
|
||||||
|
|
||||||
def setcache(self, path, index, val, self_props, props, validated):
|
def _get_path_index(self, option_bag):
|
||||||
|
if option_bag is None:
|
||||||
|
path = None
|
||||||
|
index = None
|
||||||
|
else:
|
||||||
|
path = option_bag.path
|
||||||
|
index = option_bag.index
|
||||||
|
return path, index
|
||||||
|
|
||||||
|
def getcache(self,
|
||||||
|
option_bag,
|
||||||
|
type_,
|
||||||
|
expiration=True,
|
||||||
|
):
|
||||||
|
"""get the cache value fot a specified path
|
||||||
|
"""
|
||||||
|
no_cache = False, None, False
|
||||||
|
path, index = self._get_path_index(option_bag)
|
||||||
|
if path not in self._cache or index not in self._cache[path]:
|
||||||
|
return no_cache
|
||||||
|
value, timestamp, validated = self._cache[path][index]
|
||||||
|
if type_ == 'context_props':
|
||||||
|
# cached value is settings properties so value is props
|
||||||
|
props = value
|
||||||
|
self_props = {}
|
||||||
|
else:
|
||||||
|
props = option_bag.config_bag.properties
|
||||||
|
if type_ == 'self_props':
|
||||||
|
# cached value is self_props
|
||||||
|
self_props = value
|
||||||
|
else:
|
||||||
|
self_props = option_bag.properties
|
||||||
|
if 'cache' in props or \
|
||||||
|
'cache' in self_props:
|
||||||
|
if expiration and timestamp and \
|
||||||
|
('expire' in props or \
|
||||||
|
'expire' in self_props):
|
||||||
|
ntime = int(time())
|
||||||
|
if timestamp + option_bag.config_bag.expiration_time >= ntime:
|
||||||
|
return True, value, validated
|
||||||
|
else:
|
||||||
|
return True, value, validated
|
||||||
|
return no_cache
|
||||||
|
|
||||||
|
def setcache(self,
|
||||||
|
option_bag,
|
||||||
|
val,
|
||||||
|
type_='values',
|
||||||
|
validated=True,
|
||||||
|
):
|
||||||
"""add val in cache for a specified path
|
"""add val in cache for a specified path
|
||||||
if follower, add index
|
if follower, add index
|
||||||
"""
|
"""
|
||||||
if 'cache' in props or 'cache' in self_props:
|
if type_ == 'values':
|
||||||
self._cache.setdefault(path, {})[index] = (val, int(time()), validated)
|
if 'cache' not in option_bag.config_bag.properties and \
|
||||||
|
'cache' not in option_bag.properties:
|
||||||
|
return
|
||||||
|
elif (option_bag is None or 'cache' not in option_bag.config_bag.properties) and \
|
||||||
|
'cache' not in val:
|
||||||
|
return
|
||||||
|
path, index = self._get_path_index(option_bag)
|
||||||
|
self._cache.setdefault(path, {})[index] = (val, int(time()), validated)
|
||||||
|
|
||||||
def delcache(self, path):
|
def delcache(self, path):
|
||||||
|
"""reset cache a a specified path
|
||||||
|
"""
|
||||||
if path in self._cache:
|
if path in self._cache:
|
||||||
del self._cache[path]
|
del self._cache[path]
|
||||||
|
|
||||||
def get_cached(self):
|
def get_cached(self):
|
||||||
|
"""get cache values
|
||||||
|
"""
|
||||||
return self._cache
|
return self._cache
|
||||||
|
|
||||||
def reset_all_cache(self):
|
def reset_all_cache(self):
|
||||||
|
"""reset all cache values
|
||||||
|
"""
|
||||||
self._cache.clear()
|
self._cache.clear()
|
||||||
|
|
||||||
def getcache(self,
|
|
||||||
path,
|
|
||||||
expiration_time,
|
|
||||||
index,
|
|
||||||
props,
|
|
||||||
self_props,
|
|
||||||
type_,
|
|
||||||
):
|
|
||||||
no_cache = False, None, False
|
|
||||||
if 'cache' in props or type_ == 'context_props':
|
|
||||||
values = self._cache.get(path)
|
|
||||||
if values is None:
|
|
||||||
indexed = None
|
|
||||||
else:
|
|
||||||
indexed = values.get(index)
|
|
||||||
|
|
||||||
if indexed is None:
|
|
||||||
return no_cache
|
|
||||||
value, timestamp, validated = indexed
|
|
||||||
if type_ == 'context_props':
|
|
||||||
# cached value is settings properties so value is props
|
|
||||||
props = value
|
|
||||||
elif type_ == 'self_props':
|
|
||||||
# if self_props is None, so cached value is self properties
|
|
||||||
# so value is self_props
|
|
||||||
self_props = value
|
|
||||||
# recheck "cache" value
|
|
||||||
if 'cache' in props:
|
|
||||||
if expiration_time and timestamp and \
|
|
||||||
('expire' in props or \
|
|
||||||
'expire' in self_props):
|
|
||||||
ntime = int(time())
|
|
||||||
if timestamp + expiration_time >= ntime:
|
|
||||||
# log.debug('getcache in cache (1) %s %s %s %s %s', path, value, _display_classname(self),
|
|
||||||
# id(self), index)
|
|
||||||
return True, value, validated
|
|
||||||
# else:
|
|
||||||
# log.debug('getcache expired value for path %s < %s',
|
|
||||||
# timestamp + expiration_time, ntime)
|
|
||||||
else:
|
|
||||||
# log.debug('getcache in cache (2) %s %s %s %s %s', path, value, _display_classname(self),
|
|
||||||
# id(self), index)
|
|
||||||
return True, value, validated
|
|
||||||
# log.debug('getcache %s with index %s not in %s cache',
|
|
||||||
# path, index, _display_classname(self))
|
|
||||||
return no_cache
|
|
||||||
|
|
|
@ -18,16 +18,15 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
"options handler global entry point"
|
"""options handler global entry point
|
||||||
|
"""
|
||||||
import weakref
|
import weakref
|
||||||
from copy import copy, deepcopy
|
from copy import copy, deepcopy
|
||||||
from typing import Optional, List, Any, Union
|
from typing import Optional, List, Any, Union
|
||||||
|
|
||||||
|
|
||||||
from .error import PropertiesOptionError, ConfigError, ConflictError, \
|
from .error import PropertiesOptionError, ConfigError, ConflictError, \
|
||||||
LeadershipError
|
LeadershipError
|
||||||
from .option import SynDynOptionDescription, DynOptionDescription, Leadership, Option
|
from .option import DynOptionDescription, Leadership, Option
|
||||||
from .option.baseoption import BaseOption
|
|
||||||
from .setting import OptionBag, ConfigBag, Settings, undefined, groups
|
from .setting import OptionBag, ConfigBag, Settings, undefined, groups
|
||||||
from .value import Values, owners
|
from .value import Values, owners
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
|
@ -48,7 +47,6 @@ class _SubConfig:
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
descr,
|
descr,
|
||||||
context,
|
context,
|
||||||
config_bag,
|
|
||||||
subpath=None,
|
subpath=None,
|
||||||
):
|
):
|
||||||
""" Configuration option management class
|
""" Configuration option management class
|
||||||
|
@ -60,11 +58,6 @@ class _SubConfig:
|
||||||
:type subpath: `str` with the path name
|
:type subpath: `str` with the path name
|
||||||
"""
|
"""
|
||||||
# main option description
|
# main option description
|
||||||
if __debug__ and (not isinstance(descr, (BaseOption, SynDynOptionDescription)) or
|
|
||||||
not descr.impl_is_optiondescription()):
|
|
||||||
msg = _(f'cannot create a sub config for "{descr.impl_get_display_name()}" '
|
|
||||||
f'this is a "{descr.__class__.__name__}", not an "OptionDescription"')
|
|
||||||
raise TypeError(msg)
|
|
||||||
self._impl_descr = descr
|
self._impl_descr = descr
|
||||||
self._impl_context = context
|
self._impl_context = context
|
||||||
self._impl_path = subpath
|
self._impl_path = subpath
|
||||||
|
@ -74,16 +67,6 @@ class _SubConfig:
|
||||||
):
|
):
|
||||||
"""Get the length of leader option (useful to know follower's length)
|
"""Get the length of leader option (useful to know follower's length)
|
||||||
"""
|
"""
|
||||||
if option_bag.option.impl_is_symlinkoption():
|
|
||||||
root_option_bag = OptionBag(option_bag.config_bag.context.get_description(),
|
|
||||||
None,
|
|
||||||
config_bag,
|
|
||||||
)
|
|
||||||
option_bag = self.get_sub_option_bag(root_option_bag,
|
|
||||||
option_bag.option.impl_getopt().impl_getpath(),
|
|
||||||
option_bag.index,
|
|
||||||
True,
|
|
||||||
)[-1]
|
|
||||||
cconfig_bag = option_bag.config_bag.copy()
|
cconfig_bag = option_bag.config_bag.copy()
|
||||||
cconfig_bag.remove_validation()
|
cconfig_bag.remove_validation()
|
||||||
option_bag = OptionBag(option_bag.option.get_leader(),
|
option_bag = OptionBag(option_bag.option.get_leader(),
|
||||||
|
@ -92,22 +75,22 @@ class _SubConfig:
|
||||||
)
|
)
|
||||||
return len(self.get_value(option_bag))
|
return len(self.get_value(option_bag))
|
||||||
|
|
||||||
def get_path(self):
|
|
||||||
return self._impl_path
|
|
||||||
|
|
||||||
def get_context(self):
|
|
||||||
return self._impl_context()
|
|
||||||
|
|
||||||
def get_description(self):
|
def get_description(self):
|
||||||
|
"""get root description
|
||||||
|
"""
|
||||||
assert self._impl_descr is not None, _('there is no option description for this config'
|
assert self._impl_descr is not None, _('there is no option description for this config'
|
||||||
' (may be GroupConfig)')
|
' (may be GroupConfig)')
|
||||||
return self._impl_descr
|
return self._impl_descr
|
||||||
|
|
||||||
def get_settings(self):
|
def get_settings(self):
|
||||||
return self.get_context()._impl_settings
|
"""get settings object
|
||||||
|
"""
|
||||||
|
return self._impl_settings # pylint: disable=no-member
|
||||||
|
|
||||||
def get_values(self):
|
def get_values(self):
|
||||||
return self.get_context()._impl_values
|
"""get values object
|
||||||
|
"""
|
||||||
|
return self._impl_values # pylint: disable=no-member
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# CACHE
|
# CACHE
|
||||||
|
@ -129,18 +112,24 @@ class _SubConfig:
|
||||||
)
|
)
|
||||||
option_bag.config_bag.properties = option_bag.config_bag.properties | {'cache'}
|
option_bag.config_bag.properties = option_bag.config_bag.properties | {'cache'}
|
||||||
else:
|
else:
|
||||||
context = self.get_context()
|
self._impl_values_cache.reset_all_cache() # pylint: disable=no-member
|
||||||
context._impl_values_cache.reset_all_cache()
|
self.properties_cache.reset_all_cache() # pylint: disable=no-member
|
||||||
context.properties_cache.reset_all_cache()
|
|
||||||
|
def get_values_cache(self):
|
||||||
|
"""get cache for values
|
||||||
|
"""
|
||||||
|
return self._impl_values_cache # pylint: disable=no-member
|
||||||
|
|
||||||
def reset_one_option_cache(self,
|
def reset_one_option_cache(self,
|
||||||
resetted_opts,
|
resetted_opts,
|
||||||
option_bag,
|
option_bag,
|
||||||
):
|
):
|
||||||
|
"""reset cache for one option
|
||||||
|
"""
|
||||||
if option_bag.path in resetted_opts:
|
if option_bag.path in resetted_opts:
|
||||||
return
|
return
|
||||||
resetted_opts.append(option_bag.path)
|
resetted_opts.append(option_bag.path)
|
||||||
for woption in option_bag.option._get_dependencies(option_bag.option):
|
for woption in option_bag.option._get_dependencies(option_bag.option): # pylint: disable=protected-access
|
||||||
option = woption()
|
option = woption()
|
||||||
soption_bag = OptionBag(option,
|
soption_bag = OptionBag(option,
|
||||||
option_bag.index,
|
option_bag.index,
|
||||||
|
@ -178,7 +167,6 @@ class _SubConfig:
|
||||||
subpath = ''
|
subpath = ''
|
||||||
|
|
||||||
for suffix in option_bag.option.get_suffixes(option_bag.config_bag):
|
for suffix in option_bag.option.get_suffixes(option_bag.config_bag):
|
||||||
path_suffix = option_bag.option.convert_suffix_to_path(suffix)
|
|
||||||
doption = option_bag.option.to_dynoption(subpath,
|
doption = option_bag.option.to_dynoption(subpath,
|
||||||
suffix,
|
suffix,
|
||||||
option_bag.option,
|
option_bag.option,
|
||||||
|
@ -192,7 +180,7 @@ class _SubConfig:
|
||||||
None,
|
None,
|
||||||
option_bag.config_bag,
|
option_bag.config_bag,
|
||||||
):
|
):
|
||||||
coption_bag = self.get_sub_option_bag(doption_bag,
|
coption_bag = self.get_sub_option_bag(doption_bag, # pylint: disable=no-member
|
||||||
coption.impl_getpath(),
|
coption.impl_getpath(),
|
||||||
None,
|
None,
|
||||||
False,
|
False,
|
||||||
|
@ -258,15 +246,12 @@ class _SubConfig:
|
||||||
:param first: return only one option if True, a list otherwise
|
:param first: return only one option if True, a list otherwise
|
||||||
:return: find list or an exception if nothing has been found
|
:return: find list or an exception if nothing has been found
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=too-many-arguments,too-many-locals
|
||||||
def _filter_by_value(soption_bag):
|
def _filter_by_value(soption_bag):
|
||||||
try:
|
value = self.get_value(soption_bag)
|
||||||
value = soption_bag.config_bag.context.get_value(soption_bag)
|
|
||||||
except PropertiesOptionError:
|
|
||||||
return False
|
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
return byvalue in value
|
return byvalue in value
|
||||||
else:
|
return value == byvalue
|
||||||
return value == byvalue
|
|
||||||
|
|
||||||
found = False
|
found = False
|
||||||
if only_path is not undefined:
|
if only_path is not undefined:
|
||||||
|
@ -286,10 +271,10 @@ class _SubConfig:
|
||||||
)
|
)
|
||||||
if byvalue is not undefined and not _filter_by_value(soption_bag):
|
if byvalue is not undefined and not _filter_by_value(soption_bag):
|
||||||
continue
|
continue
|
||||||
elif option_bag.config_bag.properties:
|
if option_bag.config_bag.properties:
|
||||||
#remove option with propertyerror, ...
|
#remove option with propertyerror, ...
|
||||||
try:
|
try:
|
||||||
self.get_sub_option_bag(option_bag,
|
self.get_sub_option_bag(option_bag, # pylint: disable=no-member
|
||||||
path,
|
path,
|
||||||
None,
|
None,
|
||||||
True,
|
True,
|
||||||
|
@ -331,12 +316,15 @@ class _SubConfig:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def walk(self,
|
def walk(self,
|
||||||
option_bag,
|
option_bag: OptionBag,
|
||||||
types=['option'],
|
types: List[str]=('option',),
|
||||||
group_type=None,
|
group_type=None,
|
||||||
recursive=True,
|
recursive: bool=True,
|
||||||
walked=False,
|
walked: bool=False,
|
||||||
):
|
):
|
||||||
|
"""walk to tree
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-many-branches,too-many-locals,too-many-arguments,
|
||||||
if option_bag.option.impl_is_optiondescription():
|
if option_bag.option.impl_is_optiondescription():
|
||||||
# do not return root option
|
# do not return root option
|
||||||
if walked:
|
if walked:
|
||||||
|
@ -349,7 +337,7 @@ class _SubConfig:
|
||||||
if not option_bag.option.impl_is_leadership():
|
if not option_bag.option.impl_is_leadership():
|
||||||
for opt in option_bag.option.get_children(option_bag.config_bag):
|
for opt in option_bag.option.get_children(option_bag.config_bag):
|
||||||
try:
|
try:
|
||||||
yield from self.walk(self.get_sub_option_bag(option_bag,
|
yield from self.walk(self.get_sub_option_bag(option_bag, # pylint: disable=no-member
|
||||||
opt.impl_getpath(),
|
opt.impl_getpath(),
|
||||||
None,
|
None,
|
||||||
True,
|
True,
|
||||||
|
@ -366,7 +354,7 @@ class _SubConfig:
|
||||||
# it's a leadership so walk to leader and followers
|
# it's a leadership so walk to leader and followers
|
||||||
# followers has specific length
|
# followers has specific length
|
||||||
leader, *followers = option_bag.option.get_children(option_bag.config_bag)
|
leader, *followers = option_bag.option.get_children(option_bag.config_bag)
|
||||||
leader_option_bag = self.get_sub_option_bag(option_bag,
|
leader_option_bag = self.get_sub_option_bag(option_bag, # pylint: disable=no-member
|
||||||
leader.impl_getpath(),
|
leader.impl_getpath(),
|
||||||
None,
|
None,
|
||||||
True,
|
True,
|
||||||
|
@ -375,7 +363,7 @@ class _SubConfig:
|
||||||
values = self.get_value(leader_option_bag,
|
values = self.get_value(leader_option_bag,
|
||||||
need_help=False,
|
need_help=False,
|
||||||
)
|
)
|
||||||
leadership_length = len(values)
|
ls_length = len(values)
|
||||||
try:
|
try:
|
||||||
self._walk_valid_value(leader_option_bag,
|
self._walk_valid_value(leader_option_bag,
|
||||||
types,
|
types,
|
||||||
|
@ -383,21 +371,19 @@ class _SubConfig:
|
||||||
)
|
)
|
||||||
except PropertiesOptionError as err:
|
except PropertiesOptionError as err:
|
||||||
if err.proptype in (['mandatory'], ['empty']):
|
if err.proptype in (['mandatory'], ['empty']):
|
||||||
if 'mandatory' in types:
|
yield leader_option_bag
|
||||||
yield leader_option_bag
|
for idx in range(ls_length):
|
||||||
else:
|
|
||||||
raise err
|
|
||||||
for idx in range(leadership_length):
|
|
||||||
followers_dict[idx] = []
|
followers_dict[idx] = []
|
||||||
for follower in followers:
|
for follower in followers:
|
||||||
follower_path = follower.impl_getpath()
|
follower_path = follower.impl_getpath()
|
||||||
try:
|
try:
|
||||||
for f_follower_bag in self.walk(self.get_sub_option_bag(option_bag,
|
options_bag = self.get_sub_option_bag(option_bag, # pylint: disable=no-member
|
||||||
follower_path,
|
follower_path,
|
||||||
idx,
|
idx,
|
||||||
True,
|
True,
|
||||||
leadership_length=leadership_length,
|
leadership_length=ls_length,
|
||||||
)[-1],
|
)
|
||||||
|
for f_follower_bag in self.walk(options_bag[-1],
|
||||||
types=types,
|
types=types,
|
||||||
recursive=recursive,
|
recursive=recursive,
|
||||||
group_type=group_type,
|
group_type=group_type,
|
||||||
|
@ -410,7 +396,6 @@ class _SubConfig:
|
||||||
continue
|
continue
|
||||||
if 'option' in types:
|
if 'option' in types:
|
||||||
yield followers_dict
|
yield followers_dict
|
||||||
# pass
|
|
||||||
else:
|
else:
|
||||||
if 'mandatory' in types and not option_bag.option.impl_is_symlinkoption():
|
if 'mandatory' in types and not option_bag.option.impl_is_symlinkoption():
|
||||||
try:
|
try:
|
||||||
|
@ -455,25 +440,13 @@ class _SubConfig:
|
||||||
def set_value(self,
|
def set_value(self,
|
||||||
option_bag: OptionBag,
|
option_bag: OptionBag,
|
||||||
value: Any,
|
value: Any,
|
||||||
):
|
) -> Any:
|
||||||
if option_bag.option.impl_is_symlinkoption():
|
"""set value
|
||||||
raise ConfigError(_("can't set value to a SymLinkOption"))
|
"""
|
||||||
context = option_bag.config_bag.context
|
self.get_settings().validate_properties(option_bag)
|
||||||
context.get_settings().validate_properties(option_bag)
|
return self.get_values().set_value(option_bag,
|
||||||
return context.get_values().set_value(option_bag,
|
value
|
||||||
value,
|
)
|
||||||
)
|
|
||||||
|
|
||||||
def delattr(self,
|
|
||||||
option_bag):
|
|
||||||
option = option_bag.option
|
|
||||||
if option.impl_is_symlinkoption():
|
|
||||||
raise ConfigError(_("can't delete a SymLinkOption"))
|
|
||||||
values = self.get_values()
|
|
||||||
if option_bag.index is not None:
|
|
||||||
values.reset_follower(option_bag)
|
|
||||||
else:
|
|
||||||
values.reset(option_bag)
|
|
||||||
|
|
||||||
def get_value(self,
|
def get_value(self,
|
||||||
option_bag,
|
option_bag,
|
||||||
|
@ -484,7 +457,9 @@ class _SubConfig:
|
||||||
:return: option's value if name is an option name, OptionDescription
|
:return: option's value if name is an option name, OptionDescription
|
||||||
otherwise
|
otherwise
|
||||||
"""
|
"""
|
||||||
option_bag = self._get(option_bag, parent_option_bag, need_help)
|
option_bag = self._get(option_bag,
|
||||||
|
need_help,
|
||||||
|
)
|
||||||
if isinstance(option_bag, list):
|
if isinstance(option_bag, list):
|
||||||
value = []
|
value = []
|
||||||
for opt_bag in option_bag:
|
for opt_bag in option_bag:
|
||||||
|
@ -507,10 +482,10 @@ class _SubConfig:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def _get(self,
|
def _get(self,
|
||||||
option_bag,
|
option_bag: OptionBag,
|
||||||
parent_option_bag,
|
need_help: bool,
|
||||||
need_help,
|
) -> OptionBag:
|
||||||
):
|
# pylint: disable=too-many-locals
|
||||||
option = option_bag.option
|
option = option_bag.option
|
||||||
if option.impl_is_symlinkoption():
|
if option.impl_is_symlinkoption():
|
||||||
suboption = option.impl_getopt()
|
suboption = option.impl_getopt()
|
||||||
|
@ -534,7 +509,7 @@ class _SubConfig:
|
||||||
ret.append(doption_bag)
|
ret.append(doption_bag)
|
||||||
return ret
|
return ret
|
||||||
if suboption.impl_is_follower():
|
if suboption.impl_is_follower():
|
||||||
options_bag = self.get_sub_option_bag(option_bag.config_bag,
|
options_bag = self.get_sub_option_bag(option_bag.config_bag, # pylint: disable=no-member
|
||||||
suboption.impl_getpath(),
|
suboption.impl_getpath(),
|
||||||
None,
|
None,
|
||||||
True,
|
True,
|
||||||
|
@ -554,40 +529,28 @@ class _SubConfig:
|
||||||
option_bag.config_bag,
|
option_bag.config_bag,
|
||||||
ori_option=option,
|
ori_option=option,
|
||||||
)
|
)
|
||||||
return self._get(soption_bag, None, need_help)
|
return self._get(soption_bag,
|
||||||
|
need_help,
|
||||||
|
)
|
||||||
return option_bag
|
return option_bag
|
||||||
|
|
||||||
def get_owner(self,
|
def get_owner(self, option_bag: OptionBag):
|
||||||
option_bag: OptionBag,
|
"""get owner
|
||||||
parent_option_bag=None,
|
"""
|
||||||
):
|
options_bag = self._get(option_bag,
|
||||||
options_bag = self._get(option_bag, parent_option_bag, need_help=True)
|
need_help=True,
|
||||||
|
)
|
||||||
if isinstance(options_bag, list):
|
if isinstance(options_bag, list):
|
||||||
if not option_bag.option.impl_is_symlinkoption():
|
for opt_bag in options_bag:
|
||||||
owner = []
|
owner = self.get_owner(opt_bag)
|
||||||
for opt_bag in options_bag:
|
if owner != owners.default:
|
||||||
owner.append(self.get_owner(opt_bag))
|
break
|
||||||
else:
|
else:
|
||||||
for opt_bag in options_bag:
|
owner = owners.default
|
||||||
owner = self.get_owner(opt_bag)
|
|
||||||
if owner != owners.default:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
owner = owners.default
|
|
||||||
else:
|
else:
|
||||||
owner = self.get_values().getowner(options_bag)
|
owner = self.get_values().getowner(options_bag)
|
||||||
return owner
|
return owner
|
||||||
|
|
||||||
def pop_leader(self,
|
|
||||||
option_bag: OptionBag,
|
|
||||||
leadership_option_bag: OptionBag,
|
|
||||||
index: int,
|
|
||||||
):
|
|
||||||
self.get_values().reset_leadership(option_bag,
|
|
||||||
leadership_option_bag,
|
|
||||||
index,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class _CommonConfig(_SubConfig):
|
class _CommonConfig(_SubConfig):
|
||||||
"abstract base class for the Config, KernelGroupConfig and the KernelMetaConfig"
|
"abstract base class for the Config, KernelGroupConfig and the KernelMetaConfig"
|
||||||
|
@ -597,18 +560,21 @@ class _CommonConfig(_SubConfig):
|
||||||
'properties_cache',
|
'properties_cache',
|
||||||
'_impl_permissives_cache',
|
'_impl_permissives_cache',
|
||||||
'parents',
|
'parents',
|
||||||
'impl_type')
|
'impl_type',
|
||||||
|
)
|
||||||
|
|
||||||
def _impl_build_all_caches(self, descr):
|
def _impl_build_all_caches(self, descr):
|
||||||
if not descr.impl_already_build_caches():
|
if not descr.impl_already_build_caches():
|
||||||
descr._group_type = groups.root
|
descr._group_type = groups.root # pylint: disable=protected-access
|
||||||
descr._build_cache(display_name=self._display_name)
|
descr._build_cache(display_name=self._display_name) # pylint: disable=no-member,protected-access
|
||||||
if not hasattr(descr, '_cache_force_store_values'):
|
if not hasattr(descr, '_cache_force_store_values'):
|
||||||
raise ConfigError(_('option description seems to be part of an other '
|
raise ConfigError(_('option description seems to be part of an other '
|
||||||
'config'))
|
'config'))
|
||||||
|
|
||||||
def get_parents(self):
|
def get_parents(self):
|
||||||
for parent in self.parents:
|
"""get parents
|
||||||
|
"""
|
||||||
|
for parent in self.parents: # pylint: disable=no-member
|
||||||
yield parent()
|
yield parent()
|
||||||
|
|
||||||
# information
|
# information
|
||||||
|
@ -622,22 +588,19 @@ class _CommonConfig(_SubConfig):
|
||||||
:param key: information's key (ex: "help", "doc"
|
:param key: information's key (ex: "help", "doc"
|
||||||
:param value: information's value (ex: "the help string")
|
:param value: information's value (ex: "the help string")
|
||||||
"""
|
"""
|
||||||
self._impl_values.set_information(config_bag,
|
self._impl_values.set_information(None, # pylint: disable=no-member
|
||||||
None,
|
key,
|
||||||
key,
|
value,
|
||||||
value,
|
)
|
||||||
)
|
cache = self.get_description()._cache_dependencies_information.get(key, []) # pylint: disable=protected-access
|
||||||
context = config_bag.context
|
|
||||||
cache = context.get_description()._cache_dependencies_information.get(key, [])
|
|
||||||
for option in cache:
|
for option in cache:
|
||||||
option_bag = OptionBag(option,
|
option_bag = OptionBag(option,
|
||||||
None,
|
None,
|
||||||
config_bag,
|
config_bag,
|
||||||
)
|
)
|
||||||
context.reset_cache(option_bag)
|
self.reset_cache(option_bag)
|
||||||
|
|
||||||
def impl_get_information(self,
|
def impl_get_information(self,
|
||||||
config_bag,
|
|
||||||
option_bag,
|
option_bag,
|
||||||
key,
|
key,
|
||||||
default,
|
default,
|
||||||
|
@ -646,8 +609,7 @@ class _CommonConfig(_SubConfig):
|
||||||
|
|
||||||
:param key: the item string (ex: "help")
|
:param key: the item string (ex: "help")
|
||||||
"""
|
"""
|
||||||
return self._impl_values.get_information(config_bag,
|
return self._impl_values.get_information(option_bag, # pylint: disable=no-member
|
||||||
option_bag,
|
|
||||||
key,
|
key,
|
||||||
default,
|
default,
|
||||||
)
|
)
|
||||||
|
@ -656,24 +618,27 @@ class _CommonConfig(_SubConfig):
|
||||||
key,
|
key,
|
||||||
raises=True,
|
raises=True,
|
||||||
):
|
):
|
||||||
self._impl_values.del_information(key,
|
"""delete an information
|
||||||
|
"""
|
||||||
|
self._impl_values.del_information(key, # pylint: disable=no-member
|
||||||
raises,
|
raises,
|
||||||
)
|
)
|
||||||
|
|
||||||
def impl_list_information(self):
|
def impl_list_information(self):
|
||||||
return self._impl_values.list_information()
|
"""list information keys for context
|
||||||
|
"""
|
||||||
|
return self._impl_values.list_information() # pylint: disable=no-member
|
||||||
|
|
||||||
def __getstate__(self):
|
def gen_fake_values(self) -> 'KernelConfig':
|
||||||
raise NotImplementedError()
|
"""generate a fake values to improve validation when assign a new value
|
||||||
|
"""
|
||||||
def _gen_fake_values(self):
|
export = deepcopy(self.get_values()._values) # pylint: disable=protected-access
|
||||||
export = deepcopy(self.get_values()._values)
|
|
||||||
fake_config = KernelConfig(self._impl_descr,
|
fake_config = KernelConfig(self._impl_descr,
|
||||||
force_values=export,
|
force_values=export,
|
||||||
force_settings=self.get_settings(),
|
force_settings=self.get_settings(),
|
||||||
name=self._impl_name,
|
name=self._impl_name, # pylint: disable=no-member
|
||||||
)
|
)
|
||||||
fake_config.parents = self.parents
|
fake_config.parents = self.parents # pylint: disable=no-member
|
||||||
return fake_config
|
return fake_config
|
||||||
|
|
||||||
def duplicate(self,
|
def duplicate(self,
|
||||||
|
@ -684,10 +649,11 @@ class _CommonConfig(_SubConfig):
|
||||||
deep=None,
|
deep=None,
|
||||||
name=None,
|
name=None,
|
||||||
):
|
):
|
||||||
if not isinstance(self, (KernelConfig, KernelMixConfig)):
|
"""duplication config
|
||||||
raise ConfigError(_('cannot duplicate {}').format(self.__class__.__name__))
|
"""
|
||||||
|
# pylint: disable=too-many-arguments
|
||||||
if name is None:
|
if name is None:
|
||||||
name = self._impl_name
|
name = self._impl_name # pylint: disable=no-member
|
||||||
if isinstance(self, KernelConfig):
|
if isinstance(self, KernelConfig):
|
||||||
duplicated_config = KernelConfig(self._impl_descr,
|
duplicated_config = KernelConfig(self._impl_descr,
|
||||||
_duplicate=True,
|
_duplicate=True,
|
||||||
|
@ -703,10 +669,10 @@ class _CommonConfig(_SubConfig):
|
||||||
)
|
)
|
||||||
duplicated_values = duplicated_config.get_values()
|
duplicated_values = duplicated_config.get_values()
|
||||||
duplicated_settings = duplicated_config.get_settings()
|
duplicated_settings = duplicated_config.get_settings()
|
||||||
duplicated_values._values = deepcopy(self.get_values()._values)
|
duplicated_values._values = deepcopy(self.get_values()._values) # pylint: disable=protected-access
|
||||||
duplicated_values._informations = deepcopy(self.get_values()._informations)
|
duplicated_values._informations = deepcopy(self.get_values()._informations) # pylint: disable=protected-access
|
||||||
duplicated_settings._properties = deepcopy(self.get_settings()._properties)
|
duplicated_settings._properties = deepcopy(self.get_settings()._properties) # pylint: disable=protected-access
|
||||||
duplicated_settings._permissives = deepcopy(self.get_settings()._permissives)
|
duplicated_settings._permissives = deepcopy(self.get_settings()._permissives) # pylint: disable=protected-access
|
||||||
duplicated_settings.ro_append = self.get_settings().ro_append
|
duplicated_settings.ro_append = self.get_settings().ro_append
|
||||||
duplicated_settings.rw_append = self.get_settings().rw_append
|
duplicated_settings.rw_append = self.get_settings().rw_append
|
||||||
duplicated_settings.ro_remove = self.get_settings().ro_remove
|
duplicated_settings.ro_remove = self.get_settings().ro_remove
|
||||||
|
@ -714,11 +680,11 @@ class _CommonConfig(_SubConfig):
|
||||||
duplicated_settings.default_properties = self.get_settings().default_properties
|
duplicated_settings.default_properties = self.get_settings().default_properties
|
||||||
duplicated_config.reset_cache(None, None)
|
duplicated_config.reset_cache(None, None)
|
||||||
if child is not None:
|
if child is not None:
|
||||||
duplicated_config._impl_children.append(child)
|
duplicated_config._impl_children.append(child) # pylint: disable=protected-access
|
||||||
child.parents.append(weakref.ref(duplicated_config))
|
child.parents.append(weakref.ref(duplicated_config))
|
||||||
if self.parents:
|
if self.parents: # pylint: disable=no-member
|
||||||
if deep is not None:
|
if deep is not None:
|
||||||
for parent in self.parents:
|
for parent in self.parents: # pylint: disable=no-member
|
||||||
wparent = parent()
|
wparent = parent()
|
||||||
if wparent not in deep:
|
if wparent not in deep:
|
||||||
deep.append(wparent)
|
deep.append(wparent)
|
||||||
|
@ -731,17 +697,19 @@ class _CommonConfig(_SubConfig):
|
||||||
name=subname,
|
name=subname,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
duplicated_config.parents = self.parents
|
duplicated_config.parents = self.parents # pylint: disable=no-member
|
||||||
for parent in self.parents:
|
for parent in self.parents: # pylint: disable=no-member
|
||||||
parent()._impl_children.append(duplicated_config)
|
parent()._impl_children.append(duplicated_config) # pylint: disable=protected-access
|
||||||
return duplicated_config
|
return duplicated_config
|
||||||
|
|
||||||
def get_config_path(self):
|
def get_config_path(self):
|
||||||
|
"""get config path
|
||||||
|
"""
|
||||||
path = self.impl_getname()
|
path = self.impl_getname()
|
||||||
for parent in self.parents:
|
for parent in self.parents: # pylint: disable=no-member
|
||||||
wparent = parent()
|
wparent = parent()
|
||||||
if wparent is None: # pragma: no cover
|
if wparent is None: # pragma: no cover
|
||||||
raise ConfigError(_('parent of {} not already exists').format(self._impl_name))
|
raise ConfigError(_(f'parent of {self._impl_name} not already exists')) # pylint: disable=no-member
|
||||||
path = parent().get_config_path() + '.' + path
|
path = parent().get_config_path() + '.' + path
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
@ -755,6 +723,7 @@ class _CommonConfig(_SubConfig):
|
||||||
) -> List[OptionBag]:
|
) -> List[OptionBag]:
|
||||||
"""Get the suboption for path and the name of the option
|
"""Get the suboption for path and the name of the option
|
||||||
:returns: tuple (config, name)"""
|
:returns: tuple (config, name)"""
|
||||||
|
# pylint: disable=too-many-branches,too-many-locals,too-many-arguments
|
||||||
if isinstance(bag, ConfigBag):
|
if isinstance(bag, ConfigBag):
|
||||||
option_bag = OptionBag(self.get_description(),
|
option_bag = OptionBag(self.get_description(),
|
||||||
None,
|
None,
|
||||||
|
@ -763,8 +732,6 @@ class _CommonConfig(_SubConfig):
|
||||||
else:
|
else:
|
||||||
option_bag = bag
|
option_bag = bag
|
||||||
if option_bag.option != option_bag.config_bag.context.get_description():
|
if option_bag.option != option_bag.config_bag.context.get_description():
|
||||||
if not path.startswith(option_bag.path + '.'):
|
|
||||||
raise ConfigError('cannot get sub option if not a parent')
|
|
||||||
path = path[len(option_bag.path) + 1:]
|
path = path[len(option_bag.path) + 1:]
|
||||||
path = path.split('.')
|
path = path.split('.')
|
||||||
last_idx = len(path) - 1
|
last_idx = len(path) - 1
|
||||||
|
@ -789,17 +756,18 @@ class _CommonConfig(_SubConfig):
|
||||||
option_index = None
|
option_index = None
|
||||||
if idx == last_idx:
|
if idx == last_idx:
|
||||||
if option_index is not None:
|
if option_index is not None:
|
||||||
if option.impl_is_optiondescription() or option.impl_is_symlinkoption() or not option.impl_is_follower():
|
if option.impl_is_optiondescription() or \
|
||||||
|
option.impl_is_symlinkoption() or \
|
||||||
|
not option.impl_is_follower():
|
||||||
raise ConfigError('index must be set only with a follower option')
|
raise ConfigError('index must be set only with a follower option')
|
||||||
if leadership_length is not None:
|
if leadership_length is not None:
|
||||||
length = leadership_length
|
length = leadership_length
|
||||||
else:
|
else:
|
||||||
length = self.get_length_leadership(sub_option_bag)
|
length = self.get_length_leadership(sub_option_bag)
|
||||||
if index >= length:
|
if index >= length:
|
||||||
raise LeadershipError(_('index "{}" is greater than the leadership length "{}" '
|
raise LeadershipError(_(f'index "{index}" is greater than the leadership '
|
||||||
'for option "{}"').format(index,
|
f'length "{length}" for option '
|
||||||
length,
|
f'"{option.impl_get_display_name()}"'))
|
||||||
option.impl_get_display_name()))
|
|
||||||
option_properties = properties
|
option_properties = properties
|
||||||
else:
|
else:
|
||||||
option_properties = undefined
|
option_properties = undefined
|
||||||
|
@ -815,17 +783,22 @@ class _CommonConfig(_SubConfig):
|
||||||
return options_bag
|
return options_bag
|
||||||
|
|
||||||
def impl_getname(self):
|
def impl_getname(self):
|
||||||
return self._impl_name
|
"""get config name
|
||||||
|
"""
|
||||||
|
return self._impl_name # pylint: disable=no-member
|
||||||
|
|
||||||
|
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
class KernelConfig(_CommonConfig):
|
class KernelConfig(_CommonConfig):
|
||||||
"main configuration management entry"
|
"""main configuration management entry
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-many-instance-attributes
|
||||||
__slots__ = ('__weakref__',
|
__slots__ = ('__weakref__',
|
||||||
'_impl_name',
|
'_impl_name',
|
||||||
'_display_name',
|
'_display_name',
|
||||||
'_impl_symlink',
|
'_impl_symlink',
|
||||||
'_storage')
|
'_storage',
|
||||||
|
)
|
||||||
impl_type = 'config'
|
impl_type = 'config'
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
|
@ -843,6 +816,7 @@ class KernelConfig(_CommonConfig):
|
||||||
:param context: the current root config
|
:param context: the current root config
|
||||||
:type context: `Config`
|
:type context: `Config`
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=too-many-arguments,too-many-arguments
|
||||||
self._display_name = display_name
|
self._display_name = display_name
|
||||||
self.parents = []
|
self.parents = []
|
||||||
self._impl_symlink = []
|
self._impl_symlink = []
|
||||||
|
@ -870,11 +844,12 @@ class KernelConfig(_CommonConfig):
|
||||||
super().__init__(descr,
|
super().__init__(descr,
|
||||||
self._impl_context,
|
self._impl_context,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class KernelGroupConfig(_CommonConfig):
|
class KernelGroupConfig(_CommonConfig):
|
||||||
|
"""Group a config with same optiondescription tree
|
||||||
|
"""
|
||||||
__slots__ = ('__weakref__',
|
__slots__ = ('__weakref__',
|
||||||
'_impl_children',
|
'_impl_children',
|
||||||
'_impl_name',
|
'_impl_name',
|
||||||
|
@ -886,18 +861,15 @@ class KernelGroupConfig(_CommonConfig):
|
||||||
children,
|
children,
|
||||||
display_name=None,
|
display_name=None,
|
||||||
name=None,
|
name=None,
|
||||||
_descr=None):
|
_descr=None,
|
||||||
if not isinstance(children, list):
|
):
|
||||||
raise ConfigError(_("groupconfig's children must be a list"))
|
# pylint: disable=super-init-not-called
|
||||||
names = []
|
names = []
|
||||||
for child in children:
|
for child in children:
|
||||||
if not isinstance(child, _CommonConfig):
|
|
||||||
raise ConfigError(_("groupconfig's children must be Config, MetaConfig or "
|
|
||||||
"GroupConfig"))
|
|
||||||
name_ = child._impl_name
|
name_ = child._impl_name
|
||||||
names.append(name_)
|
names.append(name_)
|
||||||
if len(names) != len(set(names)):
|
if len(names) != len(set(names)):
|
||||||
for idx in range(1, len(names) + 1):
|
while range(1, len(names) + 1):
|
||||||
name = names.pop(0)
|
name = names.pop(0)
|
||||||
if name in names:
|
if name in names:
|
||||||
raise ConflictError(_('config name must be uniq in '
|
raise ConflictError(_('config name must be uniq in '
|
||||||
|
@ -905,9 +877,6 @@ class KernelGroupConfig(_CommonConfig):
|
||||||
|
|
||||||
self._impl_children = children
|
self._impl_children = children
|
||||||
self.parents = []
|
self.parents = []
|
||||||
config_bag = ConfigBag(self,
|
|
||||||
properties=None,
|
|
||||||
permissives=None)
|
|
||||||
self._display_name = display_name
|
self._display_name = display_name
|
||||||
if name:
|
if name:
|
||||||
self._impl_name = name
|
self._impl_name = name
|
||||||
|
@ -916,6 +885,8 @@ class KernelGroupConfig(_CommonConfig):
|
||||||
self._impl_path = None
|
self._impl_path = None
|
||||||
|
|
||||||
def get_children(self):
|
def get_children(self):
|
||||||
|
"""get all children
|
||||||
|
"""
|
||||||
return self._impl_children
|
return self._impl_children
|
||||||
|
|
||||||
def reset_cache(self,
|
def reset_cache(self,
|
||||||
|
@ -972,6 +943,7 @@ class KernelGroupConfig(_CommonConfig):
|
||||||
value,
|
value,
|
||||||
)
|
)
|
||||||
except PropertiesOptionError as err:
|
except PropertiesOptionError as err:
|
||||||
|
# pylint: disable=protected-access
|
||||||
ret.append(PropertiesOptionError(err._option_bag,
|
ret.append(PropertiesOptionError(err._option_bag,
|
||||||
err.proptype,
|
err.proptype,
|
||||||
err._settings,
|
err._settings,
|
||||||
|
@ -994,6 +966,7 @@ class KernelGroupConfig(_CommonConfig):
|
||||||
):
|
):
|
||||||
"""Find first not in current KernelGroupConfig, but in each children
|
"""Find first not in current KernelGroupConfig, but in each children
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=too-many-arguments
|
||||||
# if KernelMetaConfig, all children have same OptionDescription in
|
# if KernelMetaConfig, all children have same OptionDescription in
|
||||||
# context so search only one time the option for all children
|
# context so search only one time the option for all children
|
||||||
if bypath is undefined and byname is not None and \
|
if bypath is undefined and byname is not None and \
|
||||||
|
@ -1002,14 +975,13 @@ class KernelGroupConfig(_CommonConfig):
|
||||||
None,
|
None,
|
||||||
config_bag,
|
config_bag,
|
||||||
)
|
)
|
||||||
for bypath, byoption in self.find(root_option_bag,
|
next(self.find(root_option_bag,
|
||||||
bytype=None,
|
bytype=None,
|
||||||
byname=byname,
|
byname=byname,
|
||||||
byvalue=undefined,
|
byvalue=undefined,
|
||||||
raise_if_not_found=raise_if_not_found,
|
raise_if_not_found=raise_if_not_found,
|
||||||
with_option=True,
|
with_option=True,
|
||||||
):
|
))
|
||||||
break
|
|
||||||
byname = None
|
byname = None
|
||||||
|
|
||||||
ret = []
|
ret = []
|
||||||
|
@ -1035,25 +1007,30 @@ class KernelGroupConfig(_CommonConfig):
|
||||||
None,
|
None,
|
||||||
cconfig_bag,
|
cconfig_bag,
|
||||||
)
|
)
|
||||||
for path in child.find(root_option_bag,
|
try:
|
||||||
None,
|
next(child.find(root_option_bag,
|
||||||
byname,
|
None,
|
||||||
byvalue,
|
byname,
|
||||||
raise_if_not_found=False,
|
byvalue,
|
||||||
only_path=bypath,
|
raise_if_not_found=False,
|
||||||
only_option=byoption,
|
only_path=bypath,
|
||||||
):
|
only_option=byoption,
|
||||||
|
))
|
||||||
ret.append(child)
|
ret.append(child)
|
||||||
break
|
except StopIteration:
|
||||||
|
pass
|
||||||
if not _sub:
|
if not _sub:
|
||||||
self._find_return_results(ret != [],
|
self._find_return_results(ret != [], # pylint: disable=use-implicit-booleaness-not-comparison
|
||||||
raise_if_not_found)
|
raise_if_not_found,
|
||||||
|
)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def reset(self,
|
def reset(self,
|
||||||
path: str,
|
path: str,
|
||||||
config_bag: ConfigBag,
|
config_bag: ConfigBag,
|
||||||
):
|
) -> None:
|
||||||
|
"""reset value for specified path
|
||||||
|
"""
|
||||||
for child in self._impl_children:
|
for child in self._impl_children:
|
||||||
settings = child.get_settings()
|
settings = child.get_settings()
|
||||||
cconfig_bag = config_bag.copy()
|
cconfig_bag = config_bag.copy()
|
||||||
|
@ -1072,7 +1049,10 @@ class KernelGroupConfig(_CommonConfig):
|
||||||
child.get_values().reset(option_bag)
|
child.get_values().reset(option_bag)
|
||||||
|
|
||||||
def getconfig(self,
|
def getconfig(self,
|
||||||
name):
|
name: str,
|
||||||
|
) -> KernelConfig:
|
||||||
|
"""get a child from a config name
|
||||||
|
"""
|
||||||
for child in self._impl_children:
|
for child in self._impl_children:
|
||||||
if name == child.impl_getname():
|
if name == child.impl_getname():
|
||||||
return child
|
return child
|
||||||
|
@ -1080,9 +1060,12 @@ class KernelGroupConfig(_CommonConfig):
|
||||||
|
|
||||||
|
|
||||||
class KernelMixConfig(KernelGroupConfig):
|
class KernelMixConfig(KernelGroupConfig):
|
||||||
__slots__ = ('_impl_name',
|
"""Kernel mixconfig: this config can have differents optiondescription tree
|
||||||
'_impl_symlink',
|
"""
|
||||||
'_storage')
|
# pylint: disable=too-many-instance-attributes
|
||||||
|
__slots__ = ('_impl_symlink',
|
||||||
|
'_storage',
|
||||||
|
)
|
||||||
impl_type = 'mix'
|
impl_type = 'mix'
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
|
@ -1124,6 +1107,7 @@ class KernelMixConfig(KernelGroupConfig):
|
||||||
"""only_config: could be set if you want modify value in all Config included in
|
"""only_config: could be set if you want modify value in all Config included in
|
||||||
this KernelMetaConfig
|
this KernelMetaConfig
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=too-many-branches,too-many-nested-blocks,too-many-locals,too-many-arguments
|
||||||
ret = []
|
ret = []
|
||||||
if only_config:
|
if only_config:
|
||||||
if force_default or force_default_if_same or force_dont_change_value:
|
if force_default or force_default_if_same or force_dont_change_value:
|
||||||
|
@ -1147,10 +1131,11 @@ class KernelMixConfig(KernelGroupConfig):
|
||||||
obj = self
|
obj = self
|
||||||
else:
|
else:
|
||||||
obj = child
|
obj = child
|
||||||
|
validate_properties = not force_default and not force_default_if_same
|
||||||
moption_bag = obj.get_sub_option_bag(cconfig_bag,
|
moption_bag = obj.get_sub_option_bag(cconfig_bag,
|
||||||
option_bag.path,
|
option_bag.path,
|
||||||
option_bag.index,
|
option_bag.index,
|
||||||
not force_default and not force_default_if_same,
|
validate_properties,
|
||||||
)[-1]
|
)[-1]
|
||||||
if force_default_if_same:
|
if force_default_if_same:
|
||||||
if not child.get_values().hasvalue(option_bag.path):
|
if not child.get_values().hasvalue(option_bag.path):
|
||||||
|
@ -1167,6 +1152,7 @@ class KernelMixConfig(KernelGroupConfig):
|
||||||
child_value,
|
child_value,
|
||||||
)
|
)
|
||||||
except PropertiesOptionError as err:
|
except PropertiesOptionError as err:
|
||||||
|
# pylint: disable=protected-access
|
||||||
ret.append(PropertiesOptionError(err._option_bag,
|
ret.append(PropertiesOptionError(err._option_bag,
|
||||||
err.proptype,
|
err.proptype,
|
||||||
err._settings,
|
err._settings,
|
||||||
|
@ -1198,10 +1184,13 @@ class KernelMixConfig(KernelGroupConfig):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def reset(self,
|
def reset(self,
|
||||||
path,
|
path: str,
|
||||||
only_children,
|
only_children: bool,
|
||||||
config_bag,
|
config_bag: ConfigBag,
|
||||||
):
|
) -> None:
|
||||||
|
"""reset value for a specified path
|
||||||
|
"""
|
||||||
|
# pylint: disable=arguments-differ
|
||||||
rconfig_bag = config_bag.copy()
|
rconfig_bag = config_bag.copy()
|
||||||
rconfig_bag.remove_validation()
|
rconfig_bag.remove_validation()
|
||||||
if self.impl_type == 'meta':
|
if self.impl_type == 'meta':
|
||||||
|
@ -1338,8 +1327,8 @@ class KernelMetaConfig(KernelMixConfig):
|
||||||
new_children = []
|
new_children = []
|
||||||
for child_name in children:
|
for child_name in children:
|
||||||
assert isinstance(child_name, str), _('MetaConfig with optiondescription'
|
assert isinstance(child_name, str), _('MetaConfig with optiondescription'
|
||||||
' must have string has child, '
|
' must have string has child, '
|
||||||
'not {}').format(child_name)
|
'not {}').format(child_name)
|
||||||
new_children.append(KernelConfig(optiondescription, name=child_name))
|
new_children.append(KernelConfig(optiondescription, name=child_name))
|
||||||
children = new_children
|
children = new_children
|
||||||
descr = optiondescription
|
descr = optiondescription
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
"""some functions to validates or calculates value
|
||||||
|
"""
|
||||||
from typing import Any, List, Optional
|
from typing import Any, List, Optional
|
||||||
from operator import add, mul, sub, truediv
|
from operator import add, mul, sub, truediv
|
||||||
from ipaddress import ip_address, ip_interface, ip_network
|
from ipaddress import ip_address, ip_interface, ip_network
|
||||||
|
@ -20,145 +22,130 @@ from .setting import undefined
|
||||||
from .error import display_list
|
from .error import display_list
|
||||||
|
|
||||||
|
|
||||||
def valid_network_netmask(network: str,
|
FUNCTION_WAITING_FOR_DICT = []
|
||||||
netmask: str):
|
|
||||||
"""FIXME
|
|
||||||
|
def function_waiting_for_dict(function):
|
||||||
|
"""functions (calculation or validation) receive by default only the value of other options
|
||||||
|
all functions declared with this function recieve a dict with option informations
|
||||||
|
(value, name, ...)
|
||||||
"""
|
"""
|
||||||
if isinstance(network, dict):
|
name = function.__name__
|
||||||
network_value = network['value']
|
if name not in FUNCTION_WAITING_FOR_DICT:
|
||||||
network_display_name = '({})'.format(network['name'])
|
FUNCTION_WAITING_FOR_DICT.append(name)
|
||||||
else:
|
return function
|
||||||
network_value = network
|
|
||||||
network_display_name = ''
|
|
||||||
if None in [network_value, netmask]:
|
@function_waiting_for_dict
|
||||||
|
def valid_network_netmask(network: dict,
|
||||||
|
netmask: dict,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
validates if network and netmask are coherent
|
||||||
|
this validator must be set to netmask option
|
||||||
|
"""
|
||||||
|
if None in [network['value'], netmask['value']]:
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
ip_network('{0}/{1}'.format(network_value, netmask))
|
ip_network(f'{network["value"]}/{netmask["value"]}')
|
||||||
except ValueError:
|
except ValueError as err:
|
||||||
raise ValueError(_('network "{0}" {1}does not match with this netmask').format(network_value,
|
raise ValueError(_(f'network "{network["value"]}" ({network["name"]}) does not match '
|
||||||
network_display_name))
|
'with this netmask')) from err
|
||||||
|
|
||||||
def valid_ip_netmask(ip: str,
|
|
||||||
netmask: str):
|
@function_waiting_for_dict
|
||||||
if isinstance(ip, dict):
|
def valid_ip_netmask(ip: dict, # pylint: disable=invalid-name
|
||||||
ip_value = ip['value']
|
netmask: dict,
|
||||||
ip_display_name = '({})'.format(ip['name'])
|
):
|
||||||
else:
|
"""validates if ip and netmask are coherent
|
||||||
ip_value = ip
|
this validator must be set to netmask option
|
||||||
ip_display_name = ''
|
"""
|
||||||
if None in [ip_value, netmask]:
|
if None in [ip['value'], netmask['value']]:
|
||||||
return
|
return
|
||||||
ip_netmask = ip_interface('{0}/{1}'.format(ip_value, netmask))
|
ip_netmask = ip_interface(f'{ip["value"]}/{netmask["value"]}')
|
||||||
if ip_netmask.ip == ip_netmask.network.network_address:
|
if ip_netmask.ip == ip_netmask.network.network_address:
|
||||||
raise ValueError(_('IP \"{0}\" {1}with this netmask is in fact a network address').format(ip_value, ip_display_name))
|
msg = _(f'IP "{ip["value"]}" ({ip["name"]}) with this netmask is '
|
||||||
elif ip_netmask.ip == ip_netmask.network.broadcast_address:
|
'in fact a network address')
|
||||||
raise ValueError(_('IP \"{0}\" {1}with this netmask is in fact a broacast address').format(ip_value, ip_display_name))
|
raise ValueError(msg)
|
||||||
|
if ip_netmask.ip == ip_netmask.network.broadcast_address:
|
||||||
|
msg = _(f'IP "{ip["value"]}" ({ip["name"]}) with this netmask is '
|
||||||
|
'in fact a broacast address')
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
|
||||||
# FIXME CIDR ?
|
@function_waiting_for_dict
|
||||||
def valid_broadcast(network: 'NetworkOption',
|
def valid_broadcast(network: dict,
|
||||||
netmask: 'NetmaskOption',
|
netmask: dict,
|
||||||
broadcast: 'BroadcastOption'):
|
broadcast: dict,
|
||||||
if isinstance(network, dict):
|
):
|
||||||
network_value = network['value']
|
"""validates if the broadcast is coherent with network and netmask
|
||||||
network_display_name = ' ({})'.format(network['name'])
|
"""
|
||||||
else:
|
if None in [network['value'], netmask['value'], broadcast['value']]:
|
||||||
network_value = network
|
|
||||||
network_display_name = ''
|
|
||||||
if isinstance(netmask, dict):
|
|
||||||
netmask_value = netmask['value']
|
|
||||||
netmask_display_name = ' ({})'.format(netmask['name'])
|
|
||||||
else:
|
|
||||||
netmask_value = netmask
|
|
||||||
netmask_display_name = ''
|
|
||||||
if ip_network('{0}/{1}'.format(network, netmask)).broadcast_address != ip_address(broadcast):
|
|
||||||
raise ValueError(_('broadcast invalid with network {0}{1} and netmask {2}{3}'
|
|
||||||
'').format(network_value,
|
|
||||||
network_display_name,
|
|
||||||
netmask_value,
|
|
||||||
netmask_display_name))
|
|
||||||
|
|
||||||
|
|
||||||
def valid_in_network(ip,
|
|
||||||
network,
|
|
||||||
netmask=None):
|
|
||||||
if isinstance(network, dict):
|
|
||||||
network_value = network['value']
|
|
||||||
network_display_name = ' ({})'.format(network['name'])
|
|
||||||
else:
|
|
||||||
network_value = network
|
|
||||||
network_display_name = ''
|
|
||||||
if isinstance(netmask, dict):
|
|
||||||
netmask_value = netmask['value']
|
|
||||||
netmask_display_name = ' ({})'.format(netmask['name'])
|
|
||||||
else:
|
|
||||||
netmask_value = netmask
|
|
||||||
netmask_display_name = ''
|
|
||||||
if network_value is None:
|
|
||||||
return
|
return
|
||||||
if '/' in network_value:
|
if ip_network(f'{network["value"]}/{netmask["value"]}').broadcast_address != \
|
||||||
network_obj = ip_network('{0}'.format(network_value))
|
ip_address(broadcast['value']):
|
||||||
|
msg = _(f'broadcast invalid with network {network["value"]} ({network["name"]}) '
|
||||||
|
f'and netmask {netmask["value"]} ({netmask["name"]})')
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
|
||||||
|
@function_waiting_for_dict
|
||||||
|
def valid_in_network(ip: dict, # pylint: disable=invalid-name
|
||||||
|
network: dict,
|
||||||
|
netmask=Optional[dict],
|
||||||
|
):
|
||||||
|
"""validates if an IP is in a network
|
||||||
|
this validator must be set to ip option
|
||||||
|
"""
|
||||||
|
if None in [ip['value'], network['value']]:
|
||||||
|
return
|
||||||
|
if '/' in network['value']:
|
||||||
|
# it's a CIDR network
|
||||||
|
network_value = network['value']
|
||||||
else:
|
else:
|
||||||
if netmask_value is None:
|
if netmask is None or netmask['value'] is None:
|
||||||
return
|
return
|
||||||
network_obj = ip_network('{0}/{1}'.format(network_value,
|
network_value = f'{network["value"]}/{netmask["value"]}'
|
||||||
netmask_value))
|
network_obj = ip_network(network_value)
|
||||||
if ip_interface(ip) not in network_obj:
|
ip_netmask = ip_interface(f'{ip["value"]}/{network_obj.netmask}')
|
||||||
|
if ip_netmask not in network_obj:
|
||||||
if netmask is None:
|
if netmask is None:
|
||||||
msg = _('this IP is not in network {0}{1}').format(network_value,
|
msg = _('this IP is not in network {network["value"]} ({network["name"]})')
|
||||||
network_display_name)
|
|
||||||
else:
|
else:
|
||||||
msg = _('this IP is not in network {0}{1} with netmask {2}{3}').format(network_value,
|
msg = _('this IP is not in network {network["value"]} ({network["name"]}) '
|
||||||
network_display_name,
|
'with netmask {netmask["value"]} ({netmask["name"]})')
|
||||||
netmask_value,
|
|
||||||
netmask_display_name)
|
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
# test if ip is not network/broadcast IP
|
# test if ip is not network/broadcast IP
|
||||||
ip_netmask = ip_interface('{0}/{1}'.format(ip, network_obj.netmask))
|
|
||||||
if ip_netmask.ip == ip_netmask.network.network_address:
|
if ip_netmask.ip == ip_netmask.network.network_address:
|
||||||
if netmask is None:
|
msg = _(f'this IP with the network {network["value"]} ({network["value"]} '
|
||||||
msg = _('this IP with the network {0}{1} is in fact a network address').format(network_value,
|
'is in fact a network address')
|
||||||
network_display_name)
|
|
||||||
else:
|
|
||||||
msg = _('this IP with the netmask {0}{1} is in fact a network address').format(netmask_value,
|
|
||||||
netmask_display_name)
|
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
elif ip_netmask.ip == ip_netmask.network.broadcast_address:
|
if ip_netmask.ip == ip_netmask.network.broadcast_address:
|
||||||
if netmask is None:
|
msg = _(f'this IP with the network {network["value"]} ({network["value"]} '
|
||||||
msg = _('this IP with the network {0}{1} is in fact a broadcast address').format(network_value,
|
'is in fact a broadcast address')
|
||||||
network_display_name)
|
|
||||||
else:
|
|
||||||
msg = _('this IP with the netmask {0}{1} is in fact a broadcast address').format(netmask_value,
|
|
||||||
netmask_display_name)
|
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
|
||||||
|
@function_waiting_for_dict
|
||||||
def valid_not_equal(*values):
|
def valid_not_equal(*values):
|
||||||
|
"""valid that two options have not same value
|
||||||
|
"""
|
||||||
equal = set()
|
equal = set()
|
||||||
for idx, val in enumerate(values[1:]):
|
for val in values[1:]:
|
||||||
if isinstance(val, dict):
|
if 'propertyerror' in val:
|
||||||
if 'propertyerror' in val:
|
continue
|
||||||
continue
|
if values[0]['value'] == val['value'] is not None:
|
||||||
tval = val['value']
|
equal.add(val['name'])
|
||||||
else:
|
if not equal:
|
||||||
tval = val
|
return
|
||||||
if values[0] == tval is not None:
|
msg = _(f'value is identical to {display_list(list(equal), add_quote=True)}')
|
||||||
if isinstance(val, dict):
|
raise ValueError(msg)
|
||||||
if equal is True:
|
|
||||||
equal = set()
|
|
||||||
equal.add(val['name'])
|
|
||||||
elif not equal:
|
|
||||||
equal = True
|
|
||||||
if equal:
|
|
||||||
if equal is not True:
|
|
||||||
msg = _('value is identical to {}').format(display_list(list(equal), add_quote=True))
|
|
||||||
else:
|
|
||||||
msg = _('value is identical')
|
|
||||||
raise ValueError(msg)
|
|
||||||
|
|
||||||
|
|
||||||
class CalcValue:
|
class CalcValue:
|
||||||
|
"""class to calc_value with different functions
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-many-instance-attributes
|
||||||
def __call__(self,
|
def __call__(self,
|
||||||
*args: List[Any],
|
*args: List[Any],
|
||||||
multi: bool=False,
|
multi: bool=False,
|
||||||
|
@ -175,6 +162,7 @@ class CalcValue:
|
||||||
operator: Optional[str]=None,
|
operator: Optional[str]=None,
|
||||||
index: Optional[int]=None,
|
index: Optional[int]=None,
|
||||||
**kwargs) -> Any:
|
**kwargs) -> Any:
|
||||||
|
# pylint: disable=too-many-statements,too-many-branches,too-many-nested-blocks,too-many-locals
|
||||||
"""calculate value
|
"""calculate value
|
||||||
:param args: list of value
|
:param args: list of value
|
||||||
:param multi: value returns must be a list of value
|
:param multi: value returns must be a list of value
|
||||||
|
@ -183,9 +171,11 @@ class CalcValue:
|
||||||
:param condition: test if condition is equal to expected value
|
:param condition: test if condition is equal to expected value
|
||||||
if there is more than one condition, set condition_0, condition_1, ...
|
if there is more than one condition, set condition_0, condition_1, ...
|
||||||
:param expected: value expected for all conditions
|
:param expected: value expected for all conditions
|
||||||
if expected value is different between condition, set expected_0, expected_1, ...
|
if expected value is different between condition, set expected_0,
|
||||||
|
expected_1, ...
|
||||||
:param no_condition_is_invalid: if no condition and not condition_0, condition_1, ... (for
|
:param no_condition_is_invalid: if no condition and not condition_0, condition_1, ... (for
|
||||||
example if option is disabled) consider that condition not matching
|
example if option is disabled) consider that condition not
|
||||||
|
matching
|
||||||
:param condition_operator: OR or AND operator for condition
|
:param condition_operator: OR or AND operator for condition
|
||||||
:param allow_none: if False, do not return list in None is present in list
|
:param allow_none: if False, do not return list in None is present in list
|
||||||
:param remove_duplicate_value: if True, remote duplicated value
|
:param remove_duplicate_value: if True, remote duplicated value
|
||||||
|
@ -196,28 +186,36 @@ class CalcValue:
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
* you want to copy value from an option to an other option:
|
* you want to copy value from an option to an other option:
|
||||||
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, ParamOption
|
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, \
|
||||||
|
... Params, ParamOption
|
||||||
>>> val1 = StrOption('val1', '', 'val1')
|
>>> val1 = StrOption('val1', '', 'val1')
|
||||||
>>> val2 = StrOption('val2', '', callback=calc_value, callback_params=Params(ParamOption(val1)))
|
>>> val2 = StrOption('val2', '', callback=calc_value,
|
||||||
|
... callback_params=Params(ParamOption(val1)))
|
||||||
>>> od = OptionDescription('root', '', [val1, val2])
|
>>> od = OptionDescription('root', '', [val1, val2])
|
||||||
>>> cfg = Config(od)
|
>>> cfg = Config(od)
|
||||||
>>> cfg.value.dict()
|
>>> cfg.value.dict()
|
||||||
{'val1': 'val1', 'val2': 'val1'}
|
{'val1': 'val1', 'val2': 'val1'}
|
||||||
|
|
||||||
* you want to copy values from two options in one multi option
|
* you want to copy values from two options in one multi option
|
||||||
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue
|
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, \
|
||||||
|
... ParamOption, ParamValue
|
||||||
>>> val1 = StrOption('val1', "", 'val1')
|
>>> val1 = StrOption('val1', "", 'val1')
|
||||||
>>> val2 = StrOption('val2', "", 'val2')
|
>>> val2 = StrOption('val2', "", 'val2')
|
||||||
>>> val3 = StrOption('val3', "", multi=True, callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2)), multi=ParamValue(True)))
|
>>> val3 = StrOption('val3', "", multi=True, callback=calc_value,
|
||||||
|
... callback_params=Params((ParamOption(val1), ParamOption(val2)),
|
||||||
|
... multi=ParamValue(True)))
|
||||||
>>> od = OptionDescription('root', '', [val1, val2, val3])
|
>>> od = OptionDescription('root', '', [val1, val2, val3])
|
||||||
>>> cfg = Config(od)
|
>>> cfg = Config(od)
|
||||||
>>> cfg.value.dict()
|
>>> cfg.value.dict()
|
||||||
{'val1': 'val1', 'val2': 'val2', 'val3': ['val1', 'val2']}
|
{'val1': 'val1', 'val2': 'val2', 'val3': ['val1', 'val2']}
|
||||||
|
|
||||||
* you want to copy a value from an option if it not disabled, otherwise set 'default_value'
|
* you want to copy a value from an option if it not disabled, otherwise set 'default_value'
|
||||||
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue
|
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, \
|
||||||
|
... ParamOption, ParamValue
|
||||||
>>> val1 = StrOption('val1', '', 'val1')
|
>>> val1 = StrOption('val1', '', 'val1')
|
||||||
>>> val2 = StrOption('val2', '', callback=calc_value, callback_params=Params(ParamOption(val1, True), default=ParamValue('default_value')))
|
>>> val2 = StrOption('val2', '', callback=calc_value,
|
||||||
|
... callback_params=Params(ParamOption(val1, True),
|
||||||
|
... default=ParamValue('default_value')))
|
||||||
>>> od = OptionDescription('root', '', [val1, val2])
|
>>> od = OptionDescription('root', '', [val1, val2])
|
||||||
>>> cfg = Config(od)
|
>>> cfg = Config(od)
|
||||||
>>> cfg.property.read_write()
|
>>> cfg.property.read_write()
|
||||||
|
@ -228,13 +226,15 @@ class CalcValue:
|
||||||
{'val2': 'default_value'}
|
{'val2': 'default_value'}
|
||||||
|
|
||||||
* you want to copy value from an option if an other is True, otherwise set 'default_value'
|
* you want to copy value from an option if an other is True, otherwise set 'default_value'
|
||||||
>>> from tiramisu import calc_value, BoolOption, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue
|
>>> from tiramisu import calc_value, BoolOption, StrOption, OptionDescription, Config, \
|
||||||
|
... Params, ParamOption, ParamValue
|
||||||
>>> boolean = BoolOption('boolean', '', True)
|
>>> boolean = BoolOption('boolean', '', True)
|
||||||
>>> val1 = StrOption('val1', '', 'val1')
|
>>> val1 = StrOption('val1', '', 'val1')
|
||||||
>>> val2 = StrOption('val2', '', callback=calc_value, callback_params=Params(ParamOption(val1, True),
|
>>> val2 = StrOption('val2', '', callback=calc_value,
|
||||||
... default=ParamValue('default_value'),
|
... callback_params=Params(ParamOption(val1, True),
|
||||||
... condition=ParamOption(boolean),
|
... default=ParamValue('default_value'),
|
||||||
... expected=ParamValue(True)))
|
... condition=ParamOption(boolean),
|
||||||
|
... expected=ParamValue(True)))
|
||||||
>>> od = OptionDescription('root', '', [boolean, val1, val2])
|
>>> od = OptionDescription('root', '', [boolean, val1, val2])
|
||||||
>>> cfg = Config(od)
|
>>> cfg = Config(od)
|
||||||
>>> cfg.property.read_write()
|
>>> cfg.property.read_write()
|
||||||
|
@ -245,41 +245,55 @@ class CalcValue:
|
||||||
{'boolean': False, 'val1': 'val1', 'val2': 'default_value'}
|
{'boolean': False, 'val1': 'val1', 'val2': 'default_value'}
|
||||||
|
|
||||||
* you want to copy option even if None is present
|
* you want to copy option even if None is present
|
||||||
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue
|
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, \
|
||||||
|
... ParamOption, ParamValue
|
||||||
>>> val1 = StrOption('val1', "", 'val1')
|
>>> val1 = StrOption('val1', "", 'val1')
|
||||||
>>> val2 = StrOption('val2', "")
|
>>> val2 = StrOption('val2', "")
|
||||||
>>> val3 = StrOption('val3', "", multi=True, callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2)), multi=ParamValue(True), allow_none=ParamValue(True)))
|
>>> val3 = StrOption('val3', "", multi=True, callback=calc_value,
|
||||||
|
... callback_params=Params((ParamOption(val1), ParamOption(val2)),
|
||||||
|
... multi=ParamValue(True), allow_none=ParamValue(True)))
|
||||||
>>> od = OptionDescription('root', '', [val1, val2, val3])
|
>>> od = OptionDescription('root', '', [val1, val2, val3])
|
||||||
>>> cfg = Config(od)
|
>>> cfg = Config(od)
|
||||||
>>> cfg.value.dict()
|
>>> cfg.value.dict()
|
||||||
{'val1': 'val1', 'val2': None, 'val3': ['val1', None]}
|
{'val1': 'val1', 'val2': None, 'val3': ['val1', None]}
|
||||||
|
|
||||||
* you want uniq value
|
* you want uniq value
|
||||||
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue
|
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, \
|
||||||
|
... ParamOption, ParamValue
|
||||||
>>> val1 = StrOption('val1', "", 'val1')
|
>>> val1 = StrOption('val1', "", 'val1')
|
||||||
>>> val2 = StrOption('val2', "", 'val1')
|
>>> val2 = StrOption('val2', "", 'val1')
|
||||||
>>> val3 = StrOption('val3', "", multi=True, callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2)), multi=ParamValue(True), remove_duplicate_value=ParamValue(True)))
|
>>> val3 = StrOption('val3', "", multi=True, callback=calc_value,
|
||||||
|
... callback_params=Params((ParamOption(val1), ParamOption(val2)),
|
||||||
|
... multi=ParamValue(True), remove_duplicate_value=ParamValue(True)))
|
||||||
>>> od = OptionDescription('root', '', [val1, val2, val3])
|
>>> od = OptionDescription('root', '', [val1, val2, val3])
|
||||||
>>> cfg = Config(od)
|
>>> cfg = Config(od)
|
||||||
>>> cfg.value.dict()
|
>>> cfg.value.dict()
|
||||||
{'val1': 'val1', 'val2': 'val1', 'val3': ['val1']}
|
{'val1': 'val1', 'val2': 'val1', 'val3': ['val1']}
|
||||||
|
|
||||||
* you want to join two values with '.'
|
* you want to join two values with '.'
|
||||||
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue
|
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, \
|
||||||
|
... ParamOption, ParamValue
|
||||||
>>> val1 = StrOption('val1', "", 'val1')
|
>>> val1 = StrOption('val1', "", 'val1')
|
||||||
>>> val2 = StrOption('val2', "", 'val2')
|
>>> val2 = StrOption('val2', "", 'val2')
|
||||||
>>> val3 = StrOption('val3', "", callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2)), join=ParamValue('.')))
|
>>> val3 = StrOption('val3', "", callback=calc_value,
|
||||||
|
... callback_params=Params((ParamOption(val1),
|
||||||
|
... ParamOption(val2)), join=ParamValue('.')))
|
||||||
>>> od = OptionDescription('root', '', [val1, val2, val3])
|
>>> od = OptionDescription('root', '', [val1, val2, val3])
|
||||||
>>> cfg = Config(od)
|
>>> cfg = Config(od)
|
||||||
>>> cfg.value.dict()
|
>>> cfg.value.dict()
|
||||||
{'val1': 'val1', 'val2': 'val2', 'val3': 'val1.val2'}
|
{'val1': 'val1', 'val2': 'val2', 'val3': 'val1.val2'}
|
||||||
|
|
||||||
* you want join three values, only if almost three values are set
|
* you want join three values, only if almost three values are set
|
||||||
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue
|
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, \
|
||||||
|
... ParamOption, ParamValue
|
||||||
>>> val1 = StrOption('val1', "", 'val1')
|
>>> val1 = StrOption('val1', "", 'val1')
|
||||||
>>> val2 = StrOption('val2', "", 'val2')
|
>>> val2 = StrOption('val2', "", 'val2')
|
||||||
>>> val3 = StrOption('val3', "", 'val3')
|
>>> val3 = StrOption('val3', "", 'val3')
|
||||||
>>> val4 = StrOption('val4', "", callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2), ParamOption(val3, True)), join=ParamValue('.'), min_args_len=ParamValue(3)))
|
>>> val4 = StrOption('val4', "", callback=calc_value,
|
||||||
|
... callback_params=Params((ParamOption(val1),
|
||||||
|
... ParamOption(val2),
|
||||||
|
... ParamOption(val3, True)),
|
||||||
|
... join=ParamValue('.'), min_args_len=ParamValue(3)))
|
||||||
>>> od = OptionDescription('root', '', [val1, val2, val3, val4])
|
>>> od = OptionDescription('root', '', [val1, val2, val3, val4])
|
||||||
>>> cfg = Config(od)
|
>>> cfg = Config(od)
|
||||||
>>> cfg.property.read_write()
|
>>> cfg.property.read_write()
|
||||||
|
@ -290,25 +304,31 @@ class CalcValue:
|
||||||
{'val1': 'val1', 'val2': 'val2', 'val4': ''}
|
{'val1': 'val1', 'val2': 'val2', 'val4': ''}
|
||||||
|
|
||||||
* you want to add all values
|
* you want to add all values
|
||||||
>>> from tiramisu import calc_value, IntOption, OptionDescription, Config, Params, ParamOption, ParamValue
|
>>> from tiramisu import calc_value, IntOption, OptionDescription, Config, Params, \
|
||||||
|
... ParamOption, ParamValue
|
||||||
>>> val1 = IntOption('val1', "", 1)
|
>>> val1 = IntOption('val1', "", 1)
|
||||||
>>> val2 = IntOption('val2', "", 2)
|
>>> val2 = IntOption('val2', "", 2)
|
||||||
>>> val3 = IntOption('val3', "", callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2)), operator=ParamValue('add')))
|
>>> val3 = IntOption('val3', "", callback=calc_value,
|
||||||
|
... callback_params=Params((ParamOption(val1),
|
||||||
|
ParamOption(val2)),
|
||||||
|
... operator=ParamValue('add')))
|
||||||
>>> od = OptionDescription('root', '', [val1, val2, val3])
|
>>> od = OptionDescription('root', '', [val1, val2, val3])
|
||||||
>>> cfg = Config(od)
|
>>> cfg = Config(od)
|
||||||
>>> cfg.value.dict()
|
>>> cfg.value.dict()
|
||||||
{'val1': 1, 'val2': 2, 'val3': 3}
|
{'val1': 1, 'val2': 2, 'val3': 3}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=attribute-defined-outside-init
|
||||||
self.args = args
|
self.args = args
|
||||||
self.condition = condition
|
self.condition = condition
|
||||||
self.expected = expected
|
self.expected = expected
|
||||||
self.condition_operator = condition_operator
|
self.condition_operator = condition_operator
|
||||||
self.reverse_condition = reverse_condition
|
self.reverse_condition = reverse_condition
|
||||||
self.kwargs = kwargs
|
self.kwargs = kwargs
|
||||||
self.no_condition_is_invalid = no_condition_is_invalid
|
self.no_condition_is_invalid = no_condition_is_invalid # pylint: disable=attribute-defined-outside-init
|
||||||
value = self.get_value(default,
|
value = self.get_value(default,
|
||||||
min_args_len)
|
min_args_len,
|
||||||
|
)
|
||||||
if not multi:
|
if not multi:
|
||||||
if join is not None:
|
if join is not None:
|
||||||
if None not in value:
|
if None not in value:
|
||||||
|
@ -317,12 +337,13 @@ class CalcValue:
|
||||||
value = None
|
value = None
|
||||||
elif value and operator:
|
elif value and operator:
|
||||||
new_value = value[0]
|
new_value = value[0]
|
||||||
op = {'mul': mul,
|
oper = {'mul': mul,
|
||||||
'add': add,
|
'add': add,
|
||||||
'div': truediv,
|
'div': truediv,
|
||||||
'sub': sub}[operator]
|
'sub': sub,
|
||||||
|
}[operator]
|
||||||
for val in value[1:]:
|
for val in value[1:]:
|
||||||
new_value = op(new_value, val)
|
new_value = oper(new_value, val)
|
||||||
value = new_value
|
value = new_value
|
||||||
elif value == []:
|
elif value == []:
|
||||||
value = None
|
value = None
|
||||||
|
@ -344,7 +365,9 @@ class CalcValue:
|
||||||
break
|
break
|
||||||
lval = len(val)
|
lval = len(val)
|
||||||
if length_val is not None and length_val != lval:
|
if length_val is not None and length_val != lval:
|
||||||
raise ValueError(_(f'unexpected value in calc_value with join attribute "{val}" with invalid length "{length_val}"'))
|
msg = _('unexpected value in calc_value with join attribute '
|
||||||
|
f'"{val}" with invalid length "{length_val}"')
|
||||||
|
raise ValueError(msg)
|
||||||
length_val = lval
|
length_val = lval
|
||||||
new_value = []
|
new_value = []
|
||||||
if length_val is not None:
|
if length_val is not None:
|
||||||
|
@ -374,6 +397,9 @@ class CalcValue:
|
||||||
pattern: str,
|
pattern: str,
|
||||||
to_dict: bool=False,
|
to_dict: bool=False,
|
||||||
empty_test=undefined) -> Any:
|
empty_test=undefined) -> Any:
|
||||||
|
"""get value from kwargs
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-many-branches
|
||||||
# if value attribute exist return it's value
|
# if value attribute exist return it's value
|
||||||
# otherwise pattern_0, pattern_1, ...
|
# otherwise pattern_0, pattern_1, ...
|
||||||
# otherwise undefined
|
# otherwise undefined
|
||||||
|
@ -385,10 +411,9 @@ class CalcValue:
|
||||||
else:
|
else:
|
||||||
kwargs_matches = {}
|
kwargs_matches = {}
|
||||||
len_pattern = len(pattern)
|
len_pattern = len(pattern)
|
||||||
for key in self.kwargs.keys():
|
for key, pattern_value in self.kwargs.items():
|
||||||
if key.startswith(pattern):
|
if key.startswith(pattern):
|
||||||
index = int(key[len_pattern:])
|
index = int(key[len_pattern:])
|
||||||
pattern_value = self.kwargs[key]
|
|
||||||
if isinstance(pattern_value, dict):
|
if isinstance(pattern_value, dict):
|
||||||
pattern_value = pattern_value['value']
|
pattern_value = pattern_value['value']
|
||||||
kwargs_matches[index] = pattern_value
|
kwargs_matches[index] = pattern_value
|
||||||
|
@ -408,21 +433,28 @@ class CalcValue:
|
||||||
return returns
|
return returns
|
||||||
|
|
||||||
def is_condition_matches(self,
|
def is_condition_matches(self,
|
||||||
condition_value):
|
condition_value,
|
||||||
|
):
|
||||||
|
"""verify the condition
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-many-branches
|
||||||
calculated_conditions = self.value_from_kwargs(condition_value,
|
calculated_conditions = self.value_from_kwargs(condition_value,
|
||||||
'condition_',
|
'condition_',
|
||||||
to_dict='all')
|
to_dict='all',
|
||||||
|
)
|
||||||
if calculated_conditions is undefined:
|
if calculated_conditions is undefined:
|
||||||
is_matches = not self.no_condition_is_invalid
|
is_matches = not self.no_condition_is_invalid
|
||||||
else:
|
else:
|
||||||
is_matches = None
|
is_matches = None
|
||||||
calculated_expected = self.value_from_kwargs(self.expected,
|
calculated_expected = self.value_from_kwargs(self.expected,
|
||||||
'expected_',
|
'expected_',
|
||||||
to_dict=True)
|
to_dict=True,
|
||||||
|
)
|
||||||
calculated_reverse = self.value_from_kwargs(self.reverse_condition,
|
calculated_reverse = self.value_from_kwargs(self.reverse_condition,
|
||||||
'reverse_condition_',
|
'reverse_condition_',
|
||||||
to_dict=True,
|
to_dict=True,
|
||||||
empty_test=False)
|
empty_test=False,
|
||||||
|
)
|
||||||
for idx, calculated_condition in calculated_conditions.items():
|
for idx, calculated_condition in calculated_conditions.items():
|
||||||
if isinstance(calculated_expected, dict):
|
if isinstance(calculated_expected, dict):
|
||||||
if idx is not None:
|
if idx is not None:
|
||||||
|
@ -453,14 +485,20 @@ class CalcValue:
|
||||||
if is_matches:
|
if is_matches:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise ValueError(_('unexpected {} condition_operator in calc_value').format(self.condition_operator))
|
msg = _(f'unexpected {self.condition_operator} condition_operator '
|
||||||
|
'in calc_value')
|
||||||
|
raise ValueError(msg)
|
||||||
is_matches = is_matches and not self.reverse_condition \
|
is_matches = is_matches and not self.reverse_condition \
|
||||||
or not is_matches and self.reverse_condition
|
or not is_matches and self.reverse_condition
|
||||||
return is_matches
|
return is_matches
|
||||||
|
|
||||||
def get_value(self,
|
def get_value(self,
|
||||||
default,
|
default,
|
||||||
min_args_len):
|
min_args_len,
|
||||||
|
):
|
||||||
|
"""get the value from arguments
|
||||||
|
"""
|
||||||
|
# retrieve the condition
|
||||||
if isinstance(self.condition, dict):
|
if isinstance(self.condition, dict):
|
||||||
if 'value' in self.condition:
|
if 'value' in self.condition:
|
||||||
condition_value = self.condition['value']
|
condition_value = self.condition['value']
|
||||||
|
@ -468,18 +506,19 @@ class CalcValue:
|
||||||
condition_value = undefined
|
condition_value = undefined
|
||||||
else:
|
else:
|
||||||
condition_value = self.condition
|
condition_value = self.condition
|
||||||
condition_matches = self.is_condition_matches(condition_value)
|
# value is empty if condition doesn't match
|
||||||
if not condition_matches:
|
# otherwise value is arg
|
||||||
# force to default
|
if not self.is_condition_matches(condition_value):
|
||||||
value = []
|
value = []
|
||||||
else:
|
else:
|
||||||
value = self.get_args()
|
value = self.get_args()
|
||||||
if min_args_len and not len(value) >= min_args_len:
|
if min_args_len and not len(value) >= min_args_len:
|
||||||
value = []
|
value = []
|
||||||
if value == []:
|
if not value:
|
||||||
# default value
|
# default value
|
||||||
new_default = self.value_from_kwargs(default,
|
new_default = self.value_from_kwargs(default,
|
||||||
'default_')
|
'default_',
|
||||||
|
)
|
||||||
if new_default is not undefined:
|
if new_default is not undefined:
|
||||||
if not isinstance(new_default, list):
|
if not isinstance(new_default, list):
|
||||||
value = [new_default]
|
value = [new_default]
|
||||||
|
@ -488,29 +527,34 @@ class CalcValue:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def get_args(self):
|
def get_args(self):
|
||||||
|
"""get all arguments
|
||||||
|
"""
|
||||||
return list(self.args)
|
return list(self.args)
|
||||||
|
|
||||||
|
|
||||||
class CalcValuePropertyHelp(CalcValue):
|
class CalcValuePropertyHelp(CalcValue):
|
||||||
|
"""special class to display property error
|
||||||
|
"""
|
||||||
def get_name(self):
|
def get_name(self):
|
||||||
|
"""get the condition name
|
||||||
|
"""
|
||||||
return self.condition['name']
|
return self.condition['name']
|
||||||
|
|
||||||
def get_indexed_name(self, index):
|
def get_indexed_name(self, index: int) -> str:
|
||||||
return self.kwargs.get(f'condition_{index}')['name']
|
"""get name for a specified index
|
||||||
|
"""
|
||||||
|
condition_index = self.kwargs.get(f'condition_{index}')
|
||||||
|
if condition_index is not None and not isinstance(condition_index, dict):
|
||||||
|
raise ValueError(_(f'unexpected condition_{index} must have "todict" argument'))
|
||||||
|
return condition_index['name']
|
||||||
|
|
||||||
def has_condition_kwargs(self):
|
|
||||||
for condition in self.kwargs:
|
|
||||||
if condition.startswith('condition_'):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def build_arg(self, name, value):
|
def build_property_message(self,
|
||||||
#if isinstance(option, tuple):
|
name: str,
|
||||||
# if not reverse:
|
value: Any,
|
||||||
# msg = _('the calculated value is {0}').format(display_value)
|
) -> str:
|
||||||
# else:
|
"""prepare message to display error message if needed
|
||||||
# msg = _('the calculated value is not {0}').format(display_value)
|
"""
|
||||||
#else:
|
|
||||||
if not self.reverse_condition:
|
if not self.reverse_condition:
|
||||||
msg = _('the value of "{0}" is {1}').format(name, value)
|
msg = _('the value of "{0}" is {1}').format(name, value)
|
||||||
else:
|
else:
|
||||||
|
@ -519,40 +563,35 @@ class CalcValuePropertyHelp(CalcValue):
|
||||||
|
|
||||||
def get_args(self):
|
def get_args(self):
|
||||||
args = super().get_args()
|
args = super().get_args()
|
||||||
if args:
|
action = args[0]
|
||||||
if len(self.args) != 1:
|
calculated_expected = self.value_from_kwargs(self.expected,
|
||||||
raise ValueError(_('only one property is allowed for a calculation'))
|
'expected_',
|
||||||
action = args[0]
|
to_dict=True)
|
||||||
calculated_expected = self.value_from_kwargs(self.expected,
|
if self.condition is not undefined:
|
||||||
'expected_',
|
if 'propertyerror' in self.condition:
|
||||||
to_dict=True)
|
msg = self.condition['propertyerror']
|
||||||
if self.condition is not undefined:
|
|
||||||
if 'propertyerror' in self.condition:
|
|
||||||
msg = self.condition['propertyerror']
|
|
||||||
else:
|
|
||||||
name = self.get_name()
|
|
||||||
if isinstance(calculated_expected, dict):
|
|
||||||
calc_values = calculated_expected.values()
|
|
||||||
else:
|
|
||||||
calc_values = [calculated_expected]
|
|
||||||
display_value = display_list([str(val) for val in calc_values],
|
|
||||||
'or',
|
|
||||||
add_quote=True)
|
|
||||||
msg = self.build_arg(name, display_value)
|
|
||||||
elif self.has_condition_kwargs():
|
|
||||||
msgs = []
|
|
||||||
for key, value in calculated_expected.items():
|
|
||||||
name = self.get_indexed_name(key)
|
|
||||||
msgs.append(self.build_arg(name, f'"{value}"'))
|
|
||||||
msg = display_list(msgs, self.condition_operator.lower())
|
|
||||||
else:
|
else:
|
||||||
return [(action, f'"{action}"')]
|
name = self.get_name()
|
||||||
return [(action, f'"{action}" ({msg})')]
|
if isinstance(calculated_expected, dict):
|
||||||
return
|
calc_values = calculated_expected.values()
|
||||||
## calc_properties.setdefault(action, []).append(msg)
|
else:
|
||||||
|
calc_values = [calculated_expected]
|
||||||
|
display_value = display_list([str(val) for val in calc_values],
|
||||||
|
'or',
|
||||||
|
add_quote=True)
|
||||||
|
msg = self.build_property_message(name, display_value)
|
||||||
|
else:
|
||||||
|
msgs = []
|
||||||
|
for key, value in calculated_expected.items():
|
||||||
|
name = self.get_indexed_name(key)
|
||||||
|
msgs.append(self.build_property_message(name, f'"{value}"'))
|
||||||
|
msg = display_list(msgs, self.condition_operator.lower())
|
||||||
|
return [(action, f'"{action}" ({msg})')]
|
||||||
|
|
||||||
|
|
||||||
calc_value = CalcValue()
|
calc_value = CalcValue()
|
||||||
calc_value.__name__ = 'calc_value'
|
calc_value.__name__ = 'calc_value' # pylint: disable=attribute-defined-outside-init
|
||||||
|
# function_waiting_for_dict(calc_value)
|
||||||
calc_value_property_help = CalcValuePropertyHelp()
|
calc_value_property_help = CalcValuePropertyHelp()
|
||||||
calc_value_property_help.__name__ = 'calc_value_property_help'
|
calc_value_property_help.__name__ = 'calc_value_property_help' # pylint: disable=attribute-defined-outside-init
|
||||||
|
function_waiting_for_dict(calc_value_property_help)
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
from logging import getLogger, DEBUG, basicConfig, StreamHandler, Formatter
|
from logging import getLogger, DEBUG, StreamHandler, Formatter
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,25 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2014-2023 Team tiramisu (see AUTHORS for all contributors)
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# The original `Config` design model is unproudly borrowed from
|
||||||
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
|
# the whole pypy projet is under MIT licence
|
||||||
|
# ____________________________________________________________
|
||||||
|
"""all official option
|
||||||
|
"""
|
||||||
from .optiondescription import OptionDescription
|
from .optiondescription import OptionDescription
|
||||||
from .dynoptiondescription import DynOptionDescription
|
from .dynoptiondescription import DynOptionDescription
|
||||||
from .syndynoptiondescription import SynDynOptionDescription, SynDynLeadership
|
from .syndynoptiondescription import SynDynOptionDescription, SynDynLeadership
|
||||||
|
|
|
@ -18,18 +18,16 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
from types import FunctionType
|
"""base option
|
||||||
from typing import FrozenSet, Callable, Tuple, Set, Optional, Union, Any, List
|
"""
|
||||||
|
from typing import FrozenSet, Set, Any, List
|
||||||
import weakref
|
import weakref
|
||||||
from inspect import signature
|
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from ..setting import undefined, Settings
|
from ..setting import undefined
|
||||||
from ..value import Values
|
from ..autolib import Calculation, ParamOption
|
||||||
from ..error import ConfigError, display_list
|
|
||||||
from ..autolib import Calculation, Params, ParamOption
|
|
||||||
|
|
||||||
STATIC_TUPLE = frozenset()
|
STATIC_TUPLE = frozenset()
|
||||||
|
|
||||||
|
@ -38,6 +36,8 @@ submulti = 2
|
||||||
|
|
||||||
|
|
||||||
def valid_name(name):
|
def valid_name(name):
|
||||||
|
"""valid option name
|
||||||
|
"""
|
||||||
if not isinstance(name, str):
|
if not isinstance(name, str):
|
||||||
return False
|
return False
|
||||||
# if '.' in name:
|
# if '.' in name:
|
||||||
|
@ -73,7 +73,8 @@ class Base:
|
||||||
elif isinstance(properties, tuple):
|
elif isinstance(properties, tuple):
|
||||||
properties = frozenset(properties)
|
properties = frozenset(properties)
|
||||||
if is_multi:
|
if is_multi:
|
||||||
# if option is a multi, it cannot be 'empty' (None not allowed in the list) and cannot have multiple time the same value
|
# if option is a multi, it cannot be 'empty' (None not allowed in the list)
|
||||||
|
# and cannot have multiple time the same value
|
||||||
# 'empty' and 'unique' are removed for follower's option
|
# 'empty' and 'unique' are removed for follower's option
|
||||||
if 'notunique' not in properties:
|
if 'notunique' not in properties:
|
||||||
properties = properties | {'unique'}
|
properties = properties | {'unique'}
|
||||||
|
@ -85,7 +86,8 @@ class Base:
|
||||||
for prop in properties:
|
for prop in properties:
|
||||||
if not isinstance(prop, str):
|
if not isinstance(prop, str):
|
||||||
if not isinstance(prop, Calculation):
|
if not isinstance(prop, Calculation):
|
||||||
raise ValueError(_('invalid property type {0} for {1}, must be a string or a Calculation').format(type(prop), name))
|
raise ValueError(_('invalid property type {0} for {1}, must be a string or a '
|
||||||
|
'Calculation').format(type(prop), name))
|
||||||
for param in chain(prop.params.args, prop.params.kwargs.values()):
|
for param in chain(prop.params.args, prop.params.kwargs.values()):
|
||||||
if isinstance(param, ParamOption):
|
if isinstance(param, ParamOption):
|
||||||
param.option._add_dependency(self)
|
param.option._add_dependency(self)
|
||||||
|
@ -96,7 +98,10 @@ class Base:
|
||||||
_setattr(self, '_properties', properties)
|
_setattr(self, '_properties', properties)
|
||||||
|
|
||||||
def impl_has_dependency(self,
|
def impl_has_dependency(self,
|
||||||
self_is_dep: bool=True) -> bool:
|
self_is_dep: bool=True,
|
||||||
|
) -> bool:
|
||||||
|
"""this has dependency
|
||||||
|
"""
|
||||||
if self_is_dep is True:
|
if self_is_dep is True:
|
||||||
return getattr(self, '_has_dependency', False)
|
return getattr(self, '_has_dependency', False)
|
||||||
return hasattr(self, '_dependencies')
|
return hasattr(self, '_dependencies')
|
||||||
|
@ -107,7 +112,7 @@ class Base:
|
||||||
ret = set(getattr(self, '_dependencies', STATIC_TUPLE))
|
ret = set(getattr(self, '_dependencies', STATIC_TUPLE))
|
||||||
if context_od and hasattr(context_od, '_dependencies'):
|
if context_od and hasattr(context_od, '_dependencies'):
|
||||||
# add options that have context is set in calculation
|
# add options that have context is set in calculation
|
||||||
return set(context_od._dependencies) | ret
|
return set(context_od._dependencies) | ret # pylint: disable=protected-access
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def _get_suffixes_dependencies(self) -> Set[str]:
|
def _get_suffixes_dependencies(self) -> Set[str]:
|
||||||
|
@ -119,26 +124,32 @@ class Base:
|
||||||
) -> None:
|
) -> None:
|
||||||
woption = weakref.ref(option)
|
woption = weakref.ref(option)
|
||||||
options = self._get_dependencies(None)
|
options = self._get_dependencies(None)
|
||||||
options.add(weakref.ref(option))
|
options.add(woption)
|
||||||
self._dependencies = tuple(options)
|
self._dependencies = tuple(options) # pylint: disable=attribute-defined-outside-init
|
||||||
if is_suffix:
|
if is_suffix:
|
||||||
options = list(self._get_suffixes_dependencies())
|
options = list(self._get_suffixes_dependencies())
|
||||||
options.append(weakref.ref(option))
|
options.append(woption)
|
||||||
self._suffixes_dependencies = tuple(options)
|
self._suffixes_dependencies = tuple(options) # pylint: disable=attribute-defined-outside-init
|
||||||
|
|
||||||
def impl_is_optiondescription(self) -> bool:
|
def impl_is_optiondescription(self) -> bool:
|
||||||
|
"""option is an option description
|
||||||
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def impl_is_dynoptiondescription(self) -> bool:
|
def impl_is_dynoptiondescription(self) -> bool:
|
||||||
|
"""option is not a dyn option description
|
||||||
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def impl_getname(self) -> str:
|
def impl_getname(self) -> str:
|
||||||
return self._name
|
"""get name
|
||||||
|
"""
|
||||||
|
return self._name # pylint: disable=no-member
|
||||||
|
|
||||||
def _set_readonly(self) -> None:
|
def _set_readonly(self) -> None:
|
||||||
if isinstance(self._informations, dict):
|
if isinstance(self._informations, dict): # pylint: disable=no-member
|
||||||
_setattr = object.__setattr__
|
_setattr = object.__setattr__
|
||||||
dico = self._informations
|
dico = self._informations # pylint: disable=no-member
|
||||||
keys = tuple(dico.keys())
|
keys = tuple(dico.keys())
|
||||||
if len(keys) == 1:
|
if len(keys) == 1:
|
||||||
dico = dico['doc']
|
dico = dico['doc']
|
||||||
|
@ -150,21 +161,30 @@ class Base:
|
||||||
_setattr(self, '_extra', tuple([tuple(extra.keys()), tuple(extra.values())]))
|
_setattr(self, '_extra', tuple([tuple(extra.keys()), tuple(extra.values())]))
|
||||||
|
|
||||||
def impl_is_readonly(self) -> str:
|
def impl_is_readonly(self) -> str:
|
||||||
|
"""the option is readonly
|
||||||
|
"""
|
||||||
# _path is None when initialise SymLinkOption
|
# _path is None when initialise SymLinkOption
|
||||||
return hasattr(self, '_path') and self._path is not None
|
return hasattr(self, '_path') and self._path is not None # pylint: disable=no-member
|
||||||
|
|
||||||
def impl_getproperties(self) -> FrozenSet[str]:
|
def impl_getproperties(self) -> FrozenSet[str]:
|
||||||
|
"""get properties
|
||||||
|
"""
|
||||||
return getattr(self, '_properties', frozenset())
|
return getattr(self, '_properties', frozenset())
|
||||||
|
|
||||||
def _setsubdyn(self,
|
def _setsubdyn(self,
|
||||||
subdyn,
|
subdyn,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
# pylint: disable=attribute-defined-outside-init
|
||||||
self._subdyn = subdyn
|
self._subdyn = subdyn
|
||||||
|
|
||||||
def issubdyn(self) -> bool:
|
def issubdyn(self) -> bool:
|
||||||
|
"""is sub dynoption
|
||||||
|
"""
|
||||||
return getattr(self, '_subdyn', None) is not None
|
return getattr(self, '_subdyn', None) is not None
|
||||||
|
|
||||||
def getsubdyn(self):
|
def getsubdyn(self):
|
||||||
|
"""get sub dynoption
|
||||||
|
"""
|
||||||
return self._subdyn()
|
return self._subdyn()
|
||||||
|
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
@ -177,7 +197,7 @@ class Base:
|
||||||
|
|
||||||
:param key: the item string (ex: "help")
|
:param key: the item string (ex: "help")
|
||||||
"""
|
"""
|
||||||
dico = self._informations
|
dico = self._informations # pylint: disable=no-member
|
||||||
if isinstance(dico, tuple):
|
if isinstance(dico, tuple):
|
||||||
if key in dico[0]:
|
if key in dico[0]:
|
||||||
return dico[1][dico[0].index(key)]
|
return dico[1][dico[0].index(key)]
|
||||||
|
@ -189,7 +209,9 @@ class Base:
|
||||||
return dico[key]
|
return dico[key]
|
||||||
if default is not undefined:
|
if default is not undefined:
|
||||||
return default
|
return default
|
||||||
raise ValueError(_(f'information\'s item for "{self.impl_get_display_name()}" not found: "{key}"'))
|
# pylint: disable=no-member
|
||||||
|
raise ValueError(_(f'information\'s item for "{self.impl_get_display_name()}" '
|
||||||
|
f'not found: "{key}"'))
|
||||||
|
|
||||||
def impl_set_information(self,
|
def impl_set_information(self,
|
||||||
key: str,
|
key: str,
|
||||||
|
@ -206,13 +228,15 @@ class Base:
|
||||||
" read-only").format(self.__class__.__name__,
|
" read-only").format(self.__class__.__name__,
|
||||||
self,
|
self,
|
||||||
key))
|
key))
|
||||||
self._informations[key] = value
|
self._informations[key] = value # pylint: disable=no-member
|
||||||
|
|
||||||
def impl_list_information(self) -> Any:
|
def impl_list_information(self) -> Any:
|
||||||
dico = self._informations
|
"""get the list of information keys
|
||||||
|
"""
|
||||||
|
dico = self._informations # pylint: disable=no-member
|
||||||
if isinstance(dico, tuple):
|
if isinstance(dico, tuple):
|
||||||
return list(dico[0])
|
return list(dico[0])
|
||||||
elif isinstance(dico, str):
|
if isinstance(dico, str):
|
||||||
return ['doc']
|
return ['doc']
|
||||||
# it's a dict
|
# it's a dict
|
||||||
return list(dico.keys())
|
return list(dico.keys())
|
||||||
|
@ -225,9 +249,6 @@ class BaseOption(Base):
|
||||||
"""
|
"""
|
||||||
__slots__ = ('_display_name_function',)
|
__slots__ = ('_display_name_function',)
|
||||||
|
|
||||||
def __getstate__(self):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def __setattr__(self,
|
def __setattr__(self,
|
||||||
name: str,
|
name: str,
|
||||||
value: Any) -> Any:
|
value: Any) -> Any:
|
||||||
|
@ -245,19 +266,16 @@ class BaseOption(Base):
|
||||||
' read-only').format(self.__class__.__name__,
|
' read-only').format(self.__class__.__name__,
|
||||||
self.impl_get_display_name(),
|
self.impl_get_display_name(),
|
||||||
name))
|
name))
|
||||||
super(BaseOption, self).__setattr__(name, value)
|
super().__setattr__(name, value)
|
||||||
|
|
||||||
def impl_getpath(self) -> str:
|
def impl_getpath(self) -> str:
|
||||||
|
"""get the path of the option
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
return self._path
|
return self._path
|
||||||
except AttributeError:
|
except AttributeError as err:
|
||||||
raise AttributeError(_('"{}" not part of any Config').format(self.impl_get_display_name()))
|
raise AttributeError(_(f'"{self.impl_get_display_name()}" not part of any Config')) \
|
||||||
|
from err
|
||||||
def impl_has_callback(self) -> bool:
|
|
||||||
"to know if a callback has been defined or not"
|
|
||||||
if self.impl_get_callback()[0] is not None:
|
|
||||||
print('ca existe')
|
|
||||||
return self.impl_get_callback()[0] is not None
|
|
||||||
|
|
||||||
def _impl_get_display_name(self,
|
def _impl_get_display_name(self,
|
||||||
dyn_name: Base=None,
|
dyn_name: Base=None,
|
||||||
|
@ -287,6 +305,8 @@ class BaseOption(Base):
|
||||||
)
|
)
|
||||||
|
|
||||||
def impl_get_display_name(self) -> str:
|
def impl_get_display_name(self) -> str:
|
||||||
|
"""get display name
|
||||||
|
"""
|
||||||
return self._get_display_name(None,
|
return self._get_display_name(None,
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
@ -294,19 +314,26 @@ class BaseOption(Base):
|
||||||
def reset_cache(self,
|
def reset_cache(self,
|
||||||
path: str,
|
path: str,
|
||||||
config_bag: 'OptionBag',
|
config_bag: 'OptionBag',
|
||||||
resetted_opts: List[Base]) -> None:
|
resetted_opts: List[Base], # pylint: disable=unused-argument
|
||||||
|
) -> None:
|
||||||
|
"""reset cache
|
||||||
|
"""
|
||||||
context = config_bag.context
|
context = config_bag.context
|
||||||
context.properties_cache.delcache(path)
|
context.properties_cache.delcache(path)
|
||||||
context._impl_permissives_cache.delcache(path)
|
context._impl_permissives_cache.delcache(path) # pylint: disable=protected-access
|
||||||
if not self.impl_is_optiondescription():
|
if not self.impl_is_optiondescription():
|
||||||
context._impl_values_cache.delcache(path)
|
context.get_values_cache().delcache(path) # pylint: disable=protected-access
|
||||||
|
|
||||||
def impl_is_symlinkoption(self) -> bool:
|
def impl_is_symlinkoption(self) -> bool:
|
||||||
|
"""the option is not a symlinkoption
|
||||||
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_dependencies_information(self,
|
def get_dependencies_information(self,
|
||||||
itself=False,
|
itself=False,
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
|
"""get dependencies information
|
||||||
|
"""
|
||||||
if itself:
|
if itself:
|
||||||
idx = 1
|
idx = 1
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -18,19 +18,23 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""BoolOption
|
||||||
|
"""
|
||||||
|
|
||||||
from ..setting import undefined, Undefined, OptionBag
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .option import Option
|
from .option import Option
|
||||||
|
|
||||||
|
|
||||||
class BoolOption(Option):
|
class BoolOption(Option):
|
||||||
"represents a choice between ``True`` and ``False``"
|
"""represents a choice between ``True`` and ``False``
|
||||||
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'boolean'
|
_type = _('boolean')
|
||||||
_display_name = _('boolean')
|
|
||||||
|
|
||||||
def validate(self,
|
def validate(self,
|
||||||
value: bool) -> None:
|
value: bool,
|
||||||
|
) -> None:
|
||||||
|
"""validate value
|
||||||
|
"""
|
||||||
if not isinstance(value, bool):
|
if not isinstance(value, bool):
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
|
|
|
@ -18,21 +18,25 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
from ipaddress import ip_address, ip_network
|
"""BroadcastOption
|
||||||
|
"""
|
||||||
|
from ipaddress import ip_address
|
||||||
|
|
||||||
from ..error import ConfigError
|
|
||||||
from ..setting import undefined, Undefined, OptionBag
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .option import Option
|
from .option import Option
|
||||||
|
|
||||||
|
|
||||||
class BroadcastOption(Option):
|
class BroadcastOption(Option):
|
||||||
|
"""represents the choice of a broadcast
|
||||||
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'broadcast_address'
|
_type = _('broadcast address')
|
||||||
_display_name = _('broadcast address')
|
|
||||||
|
|
||||||
def validate(self,
|
def validate(self,
|
||||||
value: str) -> None:
|
value: str,
|
||||||
|
) -> None:
|
||||||
|
"""validate
|
||||||
|
"""
|
||||||
if not isinstance(value, str):
|
if not isinstance(value, str):
|
||||||
raise ValueError(_('invalid string'))
|
raise ValueError(_('invalid string'))
|
||||||
if value.count('.') != 3:
|
if value.count('.') != 3:
|
||||||
|
@ -42,5 +46,5 @@ class BroadcastOption(Option):
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
try:
|
try:
|
||||||
ip_address(value)
|
ip_address(value)
|
||||||
except ValueError:
|
except ValueError as err:
|
||||||
raise ValueError()
|
raise ValueError() from err
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""ChoiceOption
|
||||||
|
"""
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from ..setting import undefined, OptionBag
|
from ..setting import undefined, OptionBag
|
||||||
|
@ -33,8 +35,7 @@ class ChoiceOption(Option):
|
||||||
The option can also have the value ``None``
|
The option can also have the value ``None``
|
||||||
"""
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'choice'
|
_type = _('choice')
|
||||||
_display_name = _('choice')
|
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
name,
|
name,
|
||||||
|
@ -56,7 +57,10 @@ class ChoiceOption(Option):
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
def impl_get_values(self,
|
def impl_get_values(self,
|
||||||
option_bag):
|
option_bag: OptionBag,
|
||||||
|
):
|
||||||
|
"""get values allowed by option
|
||||||
|
"""
|
||||||
if isinstance(self._choice_values, Calculation):
|
if isinstance(self._choice_values, Calculation):
|
||||||
values = self._choice_values.execute(option_bag)
|
values = self._choice_values.execute(option_bag)
|
||||||
if values is not undefined and not isinstance(values, list):
|
if values is not undefined and not isinstance(values, list):
|
||||||
|
@ -67,20 +71,18 @@ class ChoiceOption(Option):
|
||||||
return values
|
return values
|
||||||
|
|
||||||
def validate(self,
|
def validate(self,
|
||||||
value: Any) -> None:
|
value: Any,
|
||||||
pass
|
) -> None:
|
||||||
|
"""nothing to valide
|
||||||
def sync_validate_with_option(self,
|
"""
|
||||||
value: Any,
|
|
||||||
option_bag: OptionBag) -> None:
|
|
||||||
if isinstance(self._choice_values, Calculation):
|
|
||||||
return
|
|
||||||
values = self._choice_values
|
|
||||||
self.validate_values(value, values)
|
|
||||||
|
|
||||||
def validate_with_option(self,
|
def validate_with_option(self,
|
||||||
value: Any,
|
value: Any,
|
||||||
option_bag: OptionBag) -> None:
|
option_bag: OptionBag,
|
||||||
|
loaded: bool,
|
||||||
|
) -> None:
|
||||||
|
if loaded and isinstance(self._choice_values, Calculation):
|
||||||
|
return
|
||||||
values = self.impl_get_values(option_bag)
|
values = self.impl_get_values(option_bag)
|
||||||
self.validate_values(value, values)
|
self.validate_values(value, values)
|
||||||
|
|
||||||
|
@ -88,6 +90,8 @@ class ChoiceOption(Option):
|
||||||
value,
|
value,
|
||||||
values,
|
values,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
"""validate values
|
||||||
|
"""
|
||||||
if values is not undefined and value not in values:
|
if values is not undefined and value not in values:
|
||||||
if len(values) == 1:
|
if len(values) == 1:
|
||||||
raise ValueError(_('only "{0}" is allowed'
|
raise ValueError(_('only "{0}" is allowed'
|
||||||
|
|
|
@ -18,22 +18,24 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""DateOption
|
||||||
|
"""
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from ..setting import undefined, Undefined, OptionBag
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .stroption import StrOption
|
from .stroption import StrOption
|
||||||
|
|
||||||
|
|
||||||
class DateOption(StrOption):
|
class DateOption(StrOption):
|
||||||
|
"""represents the choice of a date
|
||||||
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'date'
|
_type = _('date')
|
||||||
_display_name = _('date')
|
|
||||||
|
|
||||||
def validate(self,
|
def validate(self,
|
||||||
value: str) -> None:
|
value: str) -> None:
|
||||||
super().validate(value)
|
super().validate(value)
|
||||||
try:
|
try:
|
||||||
datetime.strptime(value, "%Y-%m-%d")
|
datetime.strptime(value, "%Y-%m-%d")
|
||||||
except ValueError:
|
except ValueError as err:
|
||||||
raise ValueError()
|
raise ValueError() from err
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""DomainnameOption
|
||||||
|
"""
|
||||||
import re
|
import re
|
||||||
from ipaddress import ip_interface
|
from ipaddress import ip_interface
|
||||||
from typing import Any, Optional, List
|
from typing import Any, Optional, List
|
||||||
|
@ -38,8 +40,7 @@ class DomainnameOption(StrOption):
|
||||||
fqdn: with tld, not supported yet
|
fqdn: with tld, not supported yet
|
||||||
"""
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'domainname'
|
_type = _('domain name')
|
||||||
_display_name = _('domain name')
|
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
name: str,
|
name: str,
|
||||||
|
@ -54,8 +55,9 @@ class DomainnameOption(StrOption):
|
||||||
allow_cidr_network: bool=False,
|
allow_cidr_network: bool=False,
|
||||||
type: str='domainname',
|
type: str='domainname',
|
||||||
allow_without_dot: bool=False,
|
allow_without_dot: bool=False,
|
||||||
allow_startswith_dot: bool=False) -> None:
|
allow_startswith_dot: bool=False,
|
||||||
|
) -> None:
|
||||||
|
# pylint: disable=too-many-branches,too-many-locals,too-many-arguments
|
||||||
if type not in ['netbios', 'hostname', 'domainname']:
|
if type not in ['netbios', 'hostname', 'domainname']:
|
||||||
raise ValueError(_('unknown type {0} for hostname').format(type))
|
raise ValueError(_('unknown type {0} for hostname').format(type))
|
||||||
extra = {'_dom_type': type}
|
extra = {'_dom_type': type}
|
||||||
|
@ -111,11 +113,10 @@ class DomainnameOption(StrOption):
|
||||||
warnings_only=warnings_only,
|
warnings_only=warnings_only,
|
||||||
extra=extra)
|
extra=extra)
|
||||||
|
|
||||||
def _get_len(self, type):
|
def _get_len(self, type_):
|
||||||
if type == 'netbios':
|
if type_ == 'netbios':
|
||||||
return 15
|
return 15
|
||||||
else:
|
return 63
|
||||||
return 63
|
|
||||||
|
|
||||||
def _validate_domain(self,
|
def _validate_domain(self,
|
||||||
value: str) -> None:
|
value: str) -> None:
|
||||||
|
|
|
@ -18,9 +18,11 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""DynOptionDescription
|
||||||
|
"""
|
||||||
import re
|
import re
|
||||||
import weakref
|
import weakref
|
||||||
from typing import List, Callable, Any
|
from typing import List, Any
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from ..autolib import ParamOption
|
from ..autolib import ParamOption
|
||||||
|
|
||||||
|
@ -28,7 +30,7 @@ from ..autolib import ParamOption
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .optiondescription import OptionDescription
|
from .optiondescription import OptionDescription
|
||||||
from .baseoption import BaseOption
|
from .baseoption import BaseOption
|
||||||
from ..setting import OptionBag, ConfigBag, groups, undefined
|
from ..setting import OptionBag, ConfigBag
|
||||||
from ..error import ConfigError
|
from ..error import ConfigError
|
||||||
from ..autolib import Calculation
|
from ..autolib import Calculation
|
||||||
|
|
||||||
|
@ -37,6 +39,8 @@ NAME_REGEXP = re.compile(r'^[a-zA-Z\d\-_]*$')
|
||||||
|
|
||||||
|
|
||||||
class DynOptionDescription(OptionDescription):
|
class DynOptionDescription(OptionDescription):
|
||||||
|
"""dyn option description
|
||||||
|
"""
|
||||||
__slots__ = ('_suffixes',)
|
__slots__ = ('_suffixes',)
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
|
@ -46,7 +50,7 @@ class DynOptionDescription(OptionDescription):
|
||||||
suffixes: Calculation,
|
suffixes: Calculation,
|
||||||
properties=None,
|
properties=None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
# pylint: disable=too-many-arguments
|
||||||
super().__init__(name,
|
super().__init__(name,
|
||||||
doc,
|
doc,
|
||||||
children,
|
children,
|
||||||
|
@ -69,6 +73,8 @@ class DynOptionDescription(OptionDescription):
|
||||||
def convert_suffix_to_path(self,
|
def convert_suffix_to_path(self,
|
||||||
suffix: Any,
|
suffix: Any,
|
||||||
) -> str:
|
) -> str:
|
||||||
|
"""convert suffix to use it to a path
|
||||||
|
"""
|
||||||
if suffix is None:
|
if suffix is None:
|
||||||
return None
|
return None
|
||||||
if not isinstance(suffix, str):
|
if not isinstance(suffix, str):
|
||||||
|
@ -78,7 +84,10 @@ class DynOptionDescription(OptionDescription):
|
||||||
return suffix
|
return suffix
|
||||||
|
|
||||||
def get_suffixes(self,
|
def get_suffixes(self,
|
||||||
config_bag: ConfigBag) -> List[str]:
|
config_bag: ConfigBag,
|
||||||
|
) -> List[str]:
|
||||||
|
"""get dynamic suffixes
|
||||||
|
"""
|
||||||
option_bag = OptionBag(self,
|
option_bag = OptionBag(self,
|
||||||
None,
|
None,
|
||||||
config_bag,
|
config_bag,
|
||||||
|
@ -90,8 +99,9 @@ class DynOptionDescription(OptionDescription):
|
||||||
values_ = []
|
values_ = []
|
||||||
if __debug__:
|
if __debug__:
|
||||||
if not isinstance(values, list):
|
if not isinstance(values, list):
|
||||||
raise ValueError(_('DynOptionDescription suffixes for option "{}", is not a list ({})'
|
raise ValueError(_('DynOptionDescription suffixes for '
|
||||||
'').format(self.impl_get_display_name(), values))
|
f'option "{self.impl_get_display_name()}", is not '
|
||||||
|
f'a list ({values})'))
|
||||||
for val in values:
|
for val in values:
|
||||||
cval = self.convert_suffix_to_path(val)
|
cval = self.convert_suffix_to_path(val)
|
||||||
if not isinstance(cval, str) or re.match(NAME_REGEXP, cval) is None:
|
if not isinstance(cval, str) or re.match(NAME_REGEXP, cval) is None:
|
||||||
|
@ -106,8 +116,8 @@ class DynOptionDescription(OptionDescription):
|
||||||
extra_values = values_.copy()
|
extra_values = values_.copy()
|
||||||
for val in set(values_):
|
for val in set(values_):
|
||||||
extra_values.remove(val)
|
extra_values.remove(val)
|
||||||
raise ValueError(_('DynOptionDescription suffixes return a list with multiple value '
|
raise ValueError(_('DynOptionDescription suffixes return a list with '
|
||||||
'"{}"''').format(extra_values))
|
f'multiple value "{extra_values}"'''))
|
||||||
return values_
|
return values_
|
||||||
|
|
||||||
def impl_is_dynoptiondescription(self) -> bool:
|
def impl_is_dynoptiondescription(self) -> bool:
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""EmailOption
|
||||||
|
"""
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
|
@ -25,7 +27,8 @@ from .stroption import RegexpOption
|
||||||
|
|
||||||
|
|
||||||
class EmailOption(RegexpOption):
|
class EmailOption(RegexpOption):
|
||||||
|
"""represents a choice of an email
|
||||||
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_regexp = re.compile(r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$")
|
_regexp = re.compile(r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$")
|
||||||
_type = 'email'
|
_type = _('email address')
|
||||||
_display_name = _('email address')
|
|
||||||
|
|
|
@ -18,16 +18,17 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
import re
|
"""FilenameOption
|
||||||
|
"""
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .stroption import StrOption
|
from .stroption import StrOption
|
||||||
|
|
||||||
|
|
||||||
class FilenameOption(StrOption):
|
class FilenameOption(StrOption):
|
||||||
|
"""represents a choice of a file name
|
||||||
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'filename'
|
_type = _('file name')
|
||||||
_display_name = _('file name')
|
|
||||||
|
|
||||||
def validate(self,
|
def validate(self,
|
||||||
value: str,
|
value: str,
|
||||||
|
|
|
@ -18,17 +18,18 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""FloatOption
|
||||||
|
"""
|
||||||
|
|
||||||
from ..setting import undefined, Undefined, OptionBag
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .option import Option
|
from .option import Option
|
||||||
|
|
||||||
|
|
||||||
class FloatOption(Option):
|
class FloatOption(Option):
|
||||||
"represents a choice of a floating point number"
|
"""represents a choice of a floating point number
|
||||||
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'float'
|
_type = _('float')
|
||||||
_display_name = _('float')
|
|
||||||
|
|
||||||
def validate(self,
|
def validate(self,
|
||||||
value: float) -> None:
|
value: float) -> None:
|
||||||
|
|
|
@ -18,8 +18,9 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""IntOption
|
||||||
|
"""
|
||||||
|
|
||||||
from ..setting import undefined, Undefined, OptionBag
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .option import Option
|
from .option import Option
|
||||||
|
|
||||||
|
@ -27,8 +28,7 @@ from .option import Option
|
||||||
class IntOption(Option):
|
class IntOption(Option):
|
||||||
"represents a choice of an integer"
|
"represents a choice of an integer"
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'integer'
|
_type = _('integer')
|
||||||
_display_name = _('integer')
|
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
*args,
|
*args,
|
||||||
|
@ -43,7 +43,8 @@ class IntOption(Option):
|
||||||
super().__init__(*args, extra=extra, **kwargs)
|
super().__init__(*args, extra=extra, **kwargs)
|
||||||
|
|
||||||
def validate(self,
|
def validate(self,
|
||||||
value: int) -> None:
|
value: int,
|
||||||
|
) -> None:
|
||||||
if not isinstance(value, int):
|
if not isinstance(value, int):
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
|
|
||||||
|
|
|
@ -18,21 +18,19 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""IPOption
|
||||||
|
"""
|
||||||
from ipaddress import ip_address, ip_interface
|
from ipaddress import ip_address, ip_interface
|
||||||
|
|
||||||
from ..error import ConfigError
|
|
||||||
from ..setting import undefined, Undefined, OptionBag
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .option import Option
|
|
||||||
from .stroption import StrOption
|
from .stroption import StrOption
|
||||||
from ..function import valid_ip_netmask
|
|
||||||
|
|
||||||
|
|
||||||
class IPOption(StrOption):
|
class IPOption(StrOption):
|
||||||
"represents the choice of an ip"
|
"""represents the choice of an ip
|
||||||
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'ip'
|
_type = _('IP')
|
||||||
_display_name = _('IP')
|
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
*args,
|
*args,
|
||||||
|
@ -52,19 +50,19 @@ class IPOption(StrOption):
|
||||||
|
|
||||||
def _validate_cidr(self, value):
|
def _validate_cidr(self, value):
|
||||||
try:
|
try:
|
||||||
ip = ip_interface(value)
|
ip_obj = ip_interface(value)
|
||||||
except ValueError:
|
except ValueError as err:
|
||||||
raise ValueError()
|
raise ValueError() from err
|
||||||
if ip.ip == ip.network.network_address:
|
if ip_obj.ip == ip_obj.network.network_address:
|
||||||
raise ValueError(_("it's in fact a network address"))
|
raise ValueError(_("it's in fact a network address"))
|
||||||
elif ip.ip == ip.network.broadcast_address:
|
if ip_obj.ip == ip_obj.network.broadcast_address:
|
||||||
raise ValueError(_("it's in fact a broacast address"))
|
raise ValueError(_("it's in fact a broacast address"))
|
||||||
|
|
||||||
def _validate_ip(self, value):
|
def _validate_ip(self, value):
|
||||||
try:
|
try:
|
||||||
new_value = str(ip_address(value))
|
str(ip_address(value))
|
||||||
except ValueError:
|
except ValueError as err:
|
||||||
raise ValueError()
|
raise ValueError() from err
|
||||||
|
|
||||||
def validate(self,
|
def validate(self,
|
||||||
value: str) -> None:
|
value: str) -> None:
|
||||||
|
@ -79,14 +77,14 @@ class IPOption(StrOption):
|
||||||
def second_level_validation(self,
|
def second_level_validation(self,
|
||||||
value: str,
|
value: str,
|
||||||
warnings_only: bool) -> None:
|
warnings_only: bool) -> None:
|
||||||
ip = ip_interface(value)
|
ip_obj = ip_interface(value)
|
||||||
if not self.impl_get_extra('_allow_reserved') and ip.is_reserved:
|
if not self.impl_get_extra('_allow_reserved') and ip_obj.is_reserved:
|
||||||
if warnings_only:
|
if warnings_only:
|
||||||
msg = _("shouldn't be reserved IP")
|
msg = _("shouldn't be reserved IP")
|
||||||
else:
|
else:
|
||||||
msg = _("mustn't be reserved IP")
|
msg = _("mustn't be reserved IP")
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
if self.impl_get_extra('_private_only') and not ip.is_private:
|
if self.impl_get_extra('_private_only') and not ip_obj.is_private:
|
||||||
if warnings_only:
|
if warnings_only:
|
||||||
msg = _("should be private IP")
|
msg = _("should be private IP")
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -20,22 +20,23 @@
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
import weakref
|
import weakref
|
||||||
from itertools import chain
|
from typing import List, Iterator, Optional
|
||||||
from typing import List, Iterator, Optional, Any
|
|
||||||
|
|
||||||
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from ..setting import groups, undefined, OptionBag, Settings, ALLOWED_LEADER_PROPERTIES
|
from ..setting import groups, undefined, OptionBag, ALLOWED_LEADER_PROPERTIES
|
||||||
from ..value import Values
|
|
||||||
from .optiondescription import OptionDescription
|
from .optiondescription import OptionDescription
|
||||||
from .syndynoptiondescription import SynDynLeadership
|
from .syndynoptiondescription import SynDynLeadership
|
||||||
from .baseoption import BaseOption
|
from .baseoption import BaseOption
|
||||||
from .option import Option
|
from .option import Option
|
||||||
from ..error import LeadershipError
|
from ..error import LeadershipError
|
||||||
from ..autolib import Calculation, ParamOption
|
from ..autolib import Calculation
|
||||||
|
|
||||||
|
|
||||||
class Leadership(OptionDescription):
|
class Leadership(OptionDescription):
|
||||||
|
"""Leadership
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-many-arguments
|
||||||
__slots__ = ('leader',
|
__slots__ = ('leader',
|
||||||
'followers',
|
'followers',
|
||||||
)
|
)
|
||||||
|
@ -57,35 +58,10 @@ class Leadership(OptionDescription):
|
||||||
leader = children[0]
|
leader = children[0]
|
||||||
for idx, child in enumerate(children):
|
for idx, child in enumerate(children):
|
||||||
if __debug__:
|
if __debug__:
|
||||||
if child.impl_is_symlinkoption():
|
self._check_child_is_valid(child)
|
||||||
raise ValueError(_('leadership "{0}" shall not have '
|
|
||||||
"a symlinkoption").format(self.impl_get_display_name()))
|
|
||||||
if not isinstance(child, Option):
|
|
||||||
raise ValueError(_('leadership "{0}" shall not have '
|
|
||||||
'a subgroup').format(self.impl_get_display_name()))
|
|
||||||
if not child.impl_is_multi():
|
|
||||||
raise ValueError(_('only multi option allowed in leadership "{0}" but option '
|
|
||||||
'"{1}" is not a multi'
|
|
||||||
'').format(self.impl_get_display_name(),
|
|
||||||
child.impl_get_display_name()))
|
|
||||||
if idx != 0:
|
|
||||||
default = child.impl_getdefault()
|
|
||||||
if default != []:
|
|
||||||
if child.impl_is_submulti() and isinstance(default, tuple):
|
|
||||||
for val in default:
|
|
||||||
if not isinstance(val, Calculation):
|
|
||||||
calculation = False
|
|
||||||
else:
|
|
||||||
# empty default is valid
|
|
||||||
calculation = True
|
|
||||||
else:
|
|
||||||
calculation = isinstance(default, Calculation)
|
|
||||||
if not calculation:
|
|
||||||
raise ValueError(_('not allowed default value for follower option "{0}" '
|
|
||||||
'in leadership "{1}"'
|
|
||||||
'').format(child.impl_get_display_name(),
|
|
||||||
self.impl_get_display_name()))
|
|
||||||
if idx != 0:
|
if idx != 0:
|
||||||
|
if __debug__:
|
||||||
|
self._check_default_value(child)
|
||||||
# remove empty property for follower
|
# remove empty property for follower
|
||||||
child._properties = frozenset(child._properties - {'empty', 'unique'})
|
child._properties = frozenset(child._properties - {'empty', 'unique'})
|
||||||
followers.append(child)
|
followers.append(child)
|
||||||
|
@ -96,35 +72,78 @@ class Leadership(OptionDescription):
|
||||||
if prop not in ALLOWED_LEADER_PROPERTIES and not isinstance(prop, Calculation):
|
if prop not in ALLOWED_LEADER_PROPERTIES and not isinstance(prop, Calculation):
|
||||||
raise LeadershipError(_('leader cannot have "{}" property').format(prop))
|
raise LeadershipError(_('leader cannot have "{}" property').format(prop))
|
||||||
|
|
||||||
|
def _check_child_is_valid(self, child: BaseOption):
|
||||||
|
if child.impl_is_symlinkoption():
|
||||||
|
raise ValueError(_('leadership "{0}" shall not have '
|
||||||
|
"a symlinkoption").format(self.impl_get_display_name()))
|
||||||
|
if not isinstance(child, Option):
|
||||||
|
raise ValueError(_('leadership "{0}" shall not have '
|
||||||
|
'a subgroup').format(self.impl_get_display_name()))
|
||||||
|
if not child.impl_is_multi():
|
||||||
|
raise ValueError(_('only multi option allowed in leadership "{0}" but option '
|
||||||
|
'"{1}" is not a multi'
|
||||||
|
'').format(self.impl_get_display_name(),
|
||||||
|
child.impl_get_display_name()))
|
||||||
|
|
||||||
|
def _check_default_value(self, child: BaseOption):
|
||||||
|
default = child.impl_getdefault()
|
||||||
|
if default != []:
|
||||||
|
if child.impl_is_submulti() and isinstance(default, tuple):
|
||||||
|
for val in default:
|
||||||
|
if not isinstance(val, Calculation):
|
||||||
|
calculation = False
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# empty default is valid
|
||||||
|
calculation = True
|
||||||
|
else:
|
||||||
|
calculation = isinstance(default, Calculation)
|
||||||
|
if not calculation:
|
||||||
|
raise ValueError(_('not allowed default value for follower option '
|
||||||
|
'"{child.impl_get_display_name()}" in leadership '
|
||||||
|
'"{self.impl_get_display_name()}"'))
|
||||||
|
|
||||||
def _setsubdyn(self,
|
def _setsubdyn(self,
|
||||||
subdyn,
|
subdyn,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
# pylint: disable=attribute-defined-outside-init,protected-access
|
||||||
for chld in self._children[1]:
|
for chld in self._children[1]:
|
||||||
chld._setsubdyn(subdyn)
|
chld._setsubdyn(subdyn)
|
||||||
self._subdyn = subdyn
|
self._subdyn = subdyn
|
||||||
|
|
||||||
def is_leader(self,
|
def is_leader(self,
|
||||||
opt: Option) -> bool:
|
opt: Option,
|
||||||
|
) -> bool:
|
||||||
|
"""the option is the leader
|
||||||
|
"""
|
||||||
leader = self.get_leader()
|
leader = self.get_leader()
|
||||||
return opt == leader or (opt.impl_is_dynsymlinkoption() and opt.opt == leader)
|
return opt == leader or (opt.impl_is_dynsymlinkoption() and opt.opt == leader)
|
||||||
|
|
||||||
def get_leader(self) -> Option:
|
def get_leader(self) -> Option:
|
||||||
|
"""get leader
|
||||||
|
"""
|
||||||
return self._children[1][0]
|
return self._children[1][0]
|
||||||
|
|
||||||
def get_followers(self) -> Iterator[Option]:
|
def get_followers(self) -> Iterator[Option]:
|
||||||
|
"""get all followers
|
||||||
|
"""
|
||||||
for follower in self._children[1][1:]:
|
for follower in self._children[1][1:]:
|
||||||
yield follower
|
yield follower
|
||||||
|
|
||||||
def in_same_group(self,
|
def in_same_leadership(self,
|
||||||
opt: Option) -> bool:
|
opt: Option,
|
||||||
|
) -> bool:
|
||||||
|
"""check if followers are in same leadership
|
||||||
|
"""
|
||||||
if opt.impl_is_dynsymlinkoption():
|
if opt.impl_is_dynsymlinkoption():
|
||||||
opt = opt.opt
|
opt = opt.opt
|
||||||
return opt in self._children[1]
|
return opt in self._children[1]
|
||||||
|
|
||||||
def reset(self,
|
def reset(self, config_bag: 'ConfigBag') -> None:
|
||||||
values: Values,
|
"""reset follower value
|
||||||
option_bag: OptionBag) -> None:
|
"""
|
||||||
config_bag = option_bag.config_bag.copy()
|
values = config_bag.context.get_values()
|
||||||
|
config_bag = config_bag.copy()
|
||||||
config_bag.remove_validation()
|
config_bag.remove_validation()
|
||||||
for follower in self.get_followers():
|
for follower in self.get_followers():
|
||||||
soption_bag = OptionBag(follower,
|
soption_bag = OptionBag(follower,
|
||||||
|
@ -134,71 +153,60 @@ class Leadership(OptionDescription):
|
||||||
values.reset(soption_bag)
|
values.reset(soption_bag)
|
||||||
|
|
||||||
def follower_force_store_value(self,
|
def follower_force_store_value(self,
|
||||||
values,
|
value,
|
||||||
value,
|
config_bag: 'ConfigBag',
|
||||||
option_bag,
|
owner,
|
||||||
owner,
|
dyn=None,
|
||||||
dyn=None,
|
) -> None:
|
||||||
) -> None:
|
"""apply force_store_value to follower
|
||||||
settings = option_bag.config_bag.context.get_settings()
|
"""
|
||||||
if value:
|
if value:
|
||||||
if dyn is None:
|
if dyn is None:
|
||||||
dyn = self
|
dyn = self
|
||||||
for idx, follower in enumerate(dyn.get_children(option_bag.config_bag)):
|
values = config_bag.context.get_values()
|
||||||
|
for idx, follower in enumerate(dyn.get_children(config_bag)):
|
||||||
foption_bag = OptionBag(follower,
|
foption_bag = OptionBag(follower,
|
||||||
None,
|
None,
|
||||||
option_bag.config_bag,
|
config_bag,
|
||||||
)
|
)
|
||||||
if 'force_store_value' in foption_bag.properties:
|
if 'force_store_value' not in foption_bag.properties:
|
||||||
if idx == 0:
|
continue
|
||||||
indexes = [None]
|
if idx == 0:
|
||||||
else:
|
indexes = [None]
|
||||||
indexes = range(len(value))
|
else:
|
||||||
for index in indexes:
|
indexes = range(len(value))
|
||||||
foption_bag_index = OptionBag(follower,
|
for index in indexes:
|
||||||
index,
|
foption_bag_index = OptionBag(follower,
|
||||||
option_bag.config_bag,
|
index,
|
||||||
)
|
config_bag,
|
||||||
values.set_storage_value(foption_bag_index.path,
|
)
|
||||||
index,
|
values.set_storage_value(foption_bag_index.path,
|
||||||
values.getvalue(foption_bag_index),
|
index,
|
||||||
owner,
|
values.get_value(foption_bag_index),
|
||||||
)
|
owner,
|
||||||
|
)
|
||||||
|
|
||||||
def pop(self,
|
def pop(self,
|
||||||
values: Values,
|
|
||||||
index: int,
|
index: int,
|
||||||
option_bag: OptionBag,
|
config_bag: 'ConfigBag',
|
||||||
followers: Optional[List[Option]]=undefined,
|
followers: Optional[List[Option]]=undefined,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
"""pop leader value and follower's one
|
||||||
|
"""
|
||||||
if followers is undefined:
|
if followers is undefined:
|
||||||
# followers are not undefined only in SynDynLeadership
|
# followers are not undefined only in SynDynLeadership
|
||||||
followers = self.get_followers()
|
followers = self.get_followers()
|
||||||
config_bag = option_bag.config_bag.copy()
|
config_bag = config_bag.copy()
|
||||||
config_bag.remove_validation()
|
config_bag.remove_validation()
|
||||||
|
values = config_bag.context.get_values()
|
||||||
for follower in followers:
|
for follower in followers:
|
||||||
follower_path = follower.impl_getpath()
|
|
||||||
followerlen = values.get_max_length(follower_path)
|
|
||||||
soption_bag = OptionBag(follower,
|
soption_bag = OptionBag(follower,
|
||||||
index,
|
index,
|
||||||
config_bag,
|
config_bag,
|
||||||
properties=set(), # do not check force_default_on_freeze or force_metaconfig_on_freeze
|
properties=set(), # do not check force_default_on_freeze
|
||||||
|
# or force_metaconfig_on_freeze
|
||||||
)
|
)
|
||||||
is_default = values.is_default_owner(soption_bag,
|
values.reduce_index(soption_bag)
|
||||||
validate_meta=False,
|
|
||||||
)
|
|
||||||
if not is_default and followerlen > index:
|
|
||||||
values.resetvalue_index(follower_path,
|
|
||||||
index,
|
|
||||||
)
|
|
||||||
if followerlen > index + 1:
|
|
||||||
for idx in range(index + 1, followerlen):
|
|
||||||
if values.hasvalue(follower_path,
|
|
||||||
idx,
|
|
||||||
):
|
|
||||||
values.reduce_index(follower_path,
|
|
||||||
idx,
|
|
||||||
)
|
|
||||||
|
|
||||||
def reset_cache(self,
|
def reset_cache(self,
|
||||||
path: str,
|
path: str,
|
||||||
|
@ -221,17 +229,16 @@ class Leadership(OptionDescription):
|
||||||
) -> None:
|
) -> None:
|
||||||
super().reset_cache(path,
|
super().reset_cache(path,
|
||||||
config_bag,
|
config_bag,
|
||||||
resetted_opts)
|
resetted_opts,
|
||||||
|
)
|
||||||
leader.reset_cache(leader.impl_getpath(),
|
leader.reset_cache(leader.impl_getpath(),
|
||||||
config_bag,
|
config_bag,
|
||||||
None)
|
None)
|
||||||
for follower in followers:
|
for follower in followers:
|
||||||
spath = follower.impl_getpath()
|
follower.reset_cache(follower.impl_getpath(),
|
||||||
follower.reset_cache(spath,
|
|
||||||
config_bag,
|
config_bag,
|
||||||
None)
|
None,
|
||||||
# do not reset dependencies option
|
)
|
||||||
# resetted_opts.append(spath)
|
|
||||||
|
|
||||||
def impl_is_leadership(self) -> None:
|
def impl_is_leadership(self) -> None:
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""MACOption
|
||||||
|
"""
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
|
@ -25,7 +27,8 @@ from .stroption import RegexpOption
|
||||||
|
|
||||||
|
|
||||||
class MACOption(RegexpOption):
|
class MACOption(RegexpOption):
|
||||||
|
"""represents the choice of a mac address
|
||||||
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_regexp = re.compile(r"^([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})$")
|
_regexp = re.compile(r"^([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})$")
|
||||||
_type = 'macaddress'
|
_type = _('mac address')
|
||||||
_display_name = _('mac address')
|
|
||||||
|
|
|
@ -18,21 +18,18 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
from ipaddress import ip_interface, ip_network
|
"""NetmaskOption
|
||||||
from typing import List
|
"""
|
||||||
|
from ipaddress import ip_network
|
||||||
from ..error import ConfigError
|
|
||||||
from ..setting import undefined, OptionBag, Undefined
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .option import Option
|
|
||||||
from .stroption import StrOption
|
from .stroption import StrOption
|
||||||
|
|
||||||
|
|
||||||
class NetmaskOption(StrOption):
|
class NetmaskOption(StrOption):
|
||||||
"represents the choice of a netmask"
|
"""represents the choice of a netmask
|
||||||
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'netmask'
|
_type = _('netmask address')
|
||||||
_display_name = _('netmask address')
|
|
||||||
|
|
||||||
def validate(self,
|
def validate(self,
|
||||||
value: str) -> None:
|
value: str) -> None:
|
||||||
|
@ -41,6 +38,6 @@ class NetmaskOption(StrOption):
|
||||||
if val.startswith("0") and len(val) > 1:
|
if val.startswith("0") and len(val) > 1:
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
try:
|
try:
|
||||||
ip_network('0.0.0.0/{0}'.format(value))
|
ip_network(f'0.0.0.0/{value}')
|
||||||
except ValueError:
|
except ValueError as err:
|
||||||
raise ValueError()
|
raise ValueError() from err
|
||||||
|
|
|
@ -18,7 +18,9 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
from ipaddress import ip_address, ip_network
|
"""NetworkOption
|
||||||
|
"""
|
||||||
|
from ipaddress import ip_network
|
||||||
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .stroption import StrOption
|
from .stroption import StrOption
|
||||||
|
@ -27,8 +29,7 @@ from .stroption import StrOption
|
||||||
class NetworkOption(StrOption):
|
class NetworkOption(StrOption):
|
||||||
"represents the choice of a network"
|
"represents the choice of a network"
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'network'
|
_type = _('network address')
|
||||||
_display_name = _('network address')
|
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
*args,
|
*args,
|
||||||
|
@ -56,8 +57,8 @@ class NetworkOption(StrOption):
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
try:
|
try:
|
||||||
ip_network(value)
|
ip_network(value)
|
||||||
except ValueError:
|
except ValueError as err:
|
||||||
raise ValueError()
|
raise ValueError() from err
|
||||||
|
|
||||||
def second_level_validation(self,
|
def second_level_validation(self,
|
||||||
value: str,
|
value: str,
|
||||||
|
|
|
@ -20,21 +20,19 @@
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
import warnings
|
import warnings
|
||||||
import weakref
|
from typing import Any, List, Optional, Dict
|
||||||
from typing import Any, List, Callable, Optional, Dict, Union, Tuple
|
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
from .baseoption import BaseOption, submulti, STATIC_TUPLE
|
from .baseoption import BaseOption, submulti
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from ..setting import undefined, OptionBag, Undefined
|
from ..setting import undefined, OptionBag
|
||||||
from ..autolib import Calculation, Params, ParamOption, ParamInformation, ParamSelfInformation
|
from ..autolib import Calculation, ParamOption, ParamInformation, ParamSelfInformation
|
||||||
from ..error import (ConfigError, ValueWarning, ValueErrorWarning,
|
from ..error import ValueWarning, ValueErrorWarning, ValueOptionError
|
||||||
ValueOptionError, display_list)
|
|
||||||
from .syndynoption import SynDynOption
|
from .syndynoption import SynDynOption
|
||||||
#ALLOWED_CONST_LIST = ['_cons_not_equal']
|
|
||||||
|
|
||||||
|
|
||||||
class Option(BaseOption):
|
class Option(BaseOption):
|
||||||
|
# pylint: disable=too-many-statements,too-many-branches,too-many-arguments,too-many-locals
|
||||||
"""
|
"""
|
||||||
Abstract base class for configuration option's.
|
Abstract base class for configuration option's.
|
||||||
|
|
||||||
|
@ -55,7 +53,7 @@ class Option(BaseOption):
|
||||||
'_choice_values',
|
'_choice_values',
|
||||||
'_choice_values_params',
|
'_choice_values_params',
|
||||||
)
|
)
|
||||||
_empty = ''
|
_type = None
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
name: str,
|
name: str,
|
||||||
doc: str,
|
doc: str,
|
||||||
|
@ -99,7 +97,7 @@ class Option(BaseOption):
|
||||||
is_multi=is_multi)
|
is_multi=is_multi)
|
||||||
if validators is not None:
|
if validators is not None:
|
||||||
if __debug__ and not isinstance(validators, list):
|
if __debug__ and not isinstance(validators, list):
|
||||||
raise ValueError(_('validators must be a list of Calculation for "{}"').format(name))
|
raise ValueError(_(f'validators must be a list of Calculation for "{name}"'))
|
||||||
for validator in validators:
|
for validator in validators:
|
||||||
if __debug__ and not isinstance(validator, Calculation):
|
if __debug__ and not isinstance(validator, Calculation):
|
||||||
raise ValueError(_('validators must be a Calculation for "{}"').format(name))
|
raise ValueError(_('validators must be a Calculation for "{}"').format(name))
|
||||||
|
@ -128,19 +126,20 @@ class Option(BaseOption):
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
self.validate(value)
|
self.validate(value)
|
||||||
self.sync_validate_with_option(value,
|
self.validate_with_option(value,
|
||||||
option_bag)
|
option_bag,
|
||||||
|
loaded=True,
|
||||||
|
)
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
str_err = str(err)
|
str_err = str(err)
|
||||||
if not str_err:
|
if not str_err:
|
||||||
raise ValueError(_('invalid default_multi value "{0}" '
|
raise ValueError(_('invalid default_multi value "{0}" '
|
||||||
'for option "{1}"').format(str(value),
|
'for option "{1}"').format(str(value),
|
||||||
self.impl_get_display_name()))
|
self.impl_get_display_name())
|
||||||
else:
|
) from err
|
||||||
raise ValueError(_('invalid default_multi value "{0}" '
|
raise ValueError(_(f'invalid default_multi value "{value}" for option '
|
||||||
'for option "{1}", {2}').format(str(value),
|
f'"{self.impl_get_display_name()}", {str_err}')
|
||||||
self.impl_get_display_name(),
|
) from err
|
||||||
str_err))
|
|
||||||
if _multi is submulti:
|
if _multi is submulti:
|
||||||
if not isinstance(default_multi, Calculation):
|
if not isinstance(default_multi, Calculation):
|
||||||
if not isinstance(default_multi, list):
|
if not isinstance(default_multi, list):
|
||||||
|
@ -158,11 +157,15 @@ class Option(BaseOption):
|
||||||
undefined,
|
undefined,
|
||||||
properties=None,
|
properties=None,
|
||||||
)
|
)
|
||||||
self.sync_impl_validate(default,
|
self.impl_validate(default,
|
||||||
option_bag)
|
option_bag,
|
||||||
self.sync_impl_validate(default,
|
loaded=True,
|
||||||
option_bag,
|
)
|
||||||
check_error=False)
|
self.impl_validate(default,
|
||||||
|
option_bag,
|
||||||
|
check_error=False,
|
||||||
|
loaded=True,
|
||||||
|
)
|
||||||
self.value_dependencies(default, _dependencies_information)
|
self.value_dependencies(default, _dependencies_information)
|
||||||
if (is_multi and default != []) or \
|
if (is_multi and default != []) or \
|
||||||
(not is_multi and default is not None):
|
(not is_multi and default is not None):
|
||||||
|
@ -176,6 +179,8 @@ class Option(BaseOption):
|
||||||
value: Any,
|
value: Any,
|
||||||
_dependencies_information: List[str],
|
_dependencies_information: List[str],
|
||||||
) -> Any:
|
) -> Any:
|
||||||
|
"""parse dependancies to add dependencies
|
||||||
|
"""
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
for val in value:
|
for val in value:
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
|
@ -189,8 +194,11 @@ class Option(BaseOption):
|
||||||
value: Any,
|
value: Any,
|
||||||
_dependencies_information: List[str],
|
_dependencies_information: List[str],
|
||||||
) -> Any:
|
) -> Any:
|
||||||
|
"""parse dependancy to add dependencies
|
||||||
|
"""
|
||||||
for param in chain(value.params.args, value.params.kwargs.values()):
|
for param in chain(value.params.args, value.params.kwargs.values()):
|
||||||
if isinstance(param, ParamOption):
|
if isinstance(param, ParamOption):
|
||||||
|
# pylint: disable=protected-access
|
||||||
param.option._add_dependency(self)
|
param.option._add_dependency(self)
|
||||||
elif isinstance(param, ParamSelfInformation):
|
elif isinstance(param, ParamSelfInformation):
|
||||||
_dependencies_information[1].append(param.information_name)
|
_dependencies_information[1].append(param.information_name)
|
||||||
|
@ -201,23 +209,28 @@ class Option(BaseOption):
|
||||||
# option's information
|
# option's information
|
||||||
|
|
||||||
def impl_is_multi(self) -> bool:
|
def impl_is_multi(self) -> bool:
|
||||||
|
"""is it a multi option
|
||||||
|
"""
|
||||||
return getattr(self, '_multi', 1) != 1
|
return getattr(self, '_multi', 1) != 1
|
||||||
|
|
||||||
def impl_is_submulti(self) -> bool:
|
def impl_is_submulti(self) -> bool:
|
||||||
|
"""is it a submulti option
|
||||||
|
"""
|
||||||
return getattr(self, '_multi', 1) == 2
|
return getattr(self, '_multi', 1) == 2
|
||||||
|
|
||||||
def impl_is_dynsymlinkoption(self) -> bool:
|
def impl_is_dynsymlinkoption(self) -> bool:
|
||||||
|
"""is a dynsymlinkoption?
|
||||||
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_type(self) -> str:
|
def get_type(self) -> str:
|
||||||
# _display_name for compatibility with older version than 3.0rc3
|
"""get the type of option
|
||||||
return getattr(self, '_type', self._display_name)
|
"""
|
||||||
|
return self._type
|
||||||
def get_display_type(self) -> str:
|
|
||||||
return self._display_name
|
|
||||||
|
|
||||||
def impl_getdefault(self) -> Any:
|
def impl_getdefault(self) -> Any:
|
||||||
"accessing the default value"
|
"""accessing the default value
|
||||||
|
"""
|
||||||
is_multi = self.impl_is_multi()
|
is_multi = self.impl_is_multi()
|
||||||
default = getattr(self, '_default', undefined)
|
default = getattr(self, '_default', undefined)
|
||||||
if default is undefined:
|
if default is undefined:
|
||||||
|
@ -225,13 +238,13 @@ class Option(BaseOption):
|
||||||
default = []
|
default = []
|
||||||
else:
|
else:
|
||||||
default = None
|
default = None
|
||||||
else:
|
elif is_multi and isinstance(default, tuple):
|
||||||
if is_multi and isinstance(default, list):
|
default = list(default)
|
||||||
default = list(default)
|
|
||||||
return default
|
return default
|
||||||
|
|
||||||
def impl_getdefault_multi(self) -> Any:
|
def impl_getdefault_multi(self) -> Any:
|
||||||
"accessing the default value for a multi"
|
"""accessing the default value for a multi
|
||||||
|
"""
|
||||||
if self.impl_is_submulti():
|
if self.impl_is_submulti():
|
||||||
default_value = []
|
default_value = []
|
||||||
else:
|
else:
|
||||||
|
@ -239,93 +252,25 @@ class Option(BaseOption):
|
||||||
return getattr(self, '_default_multi', default_value)
|
return getattr(self, '_default_multi', default_value)
|
||||||
|
|
||||||
def impl_get_extra(self,
|
def impl_get_extra(self,
|
||||||
key: str) -> Any:
|
key: str,
|
||||||
|
) -> Any:
|
||||||
|
"""if extra parameters are store get it
|
||||||
|
"""
|
||||||
extra = getattr(self, '_extra', {})
|
extra = getattr(self, '_extra', {})
|
||||||
if isinstance(extra, tuple):
|
if isinstance(extra, tuple):
|
||||||
if key in extra[0]:
|
if key in extra[0]:
|
||||||
return extra[1][extra[0].index(key)]
|
return extra[1][extra[0].index(key)]
|
||||||
return None
|
return None
|
||||||
else:
|
return extra.get(key)
|
||||||
return extra.get(key)
|
|
||||||
|
|
||||||
#__________________________________________________________________________
|
#__________________________________________________________________________
|
||||||
# validator
|
# validator
|
||||||
def sync_impl_validate(self,
|
|
||||||
value: Any,
|
|
||||||
option_bag: OptionBag,
|
|
||||||
check_error: bool=True) -> None:
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
is_warnings_only = getattr(self, '_warnings_only', False)
|
|
||||||
|
|
||||||
def do_validation(_value,
|
|
||||||
_index):
|
|
||||||
if isinstance(_value, list):
|
|
||||||
raise ValueError(_('which must not be a list').format(_value,
|
|
||||||
self.impl_get_display_name()))
|
|
||||||
if _value is not None:
|
|
||||||
if check_error:
|
|
||||||
# option validation
|
|
||||||
self.validate(_value)
|
|
||||||
self.sync_validate_with_option(_value,
|
|
||||||
option_bag)
|
|
||||||
if ((check_error and not is_warnings_only) or
|
|
||||||
(not check_error and is_warnings_only)):
|
|
||||||
try:
|
|
||||||
self.second_level_validation(_value,
|
|
||||||
is_warnings_only)
|
|
||||||
except ValueError as err:
|
|
||||||
if is_warnings_only:
|
|
||||||
warnings.warn_explicit(ValueWarning(_value,
|
|
||||||
self._display_name,
|
|
||||||
self,
|
|
||||||
'{0}'.format(err),
|
|
||||||
_index),
|
|
||||||
ValueWarning,
|
|
||||||
self.__class__.__name__, 0)
|
|
||||||
else:
|
|
||||||
raise err
|
|
||||||
try:
|
|
||||||
err_index = None
|
|
||||||
if isinstance(value, Calculation):
|
|
||||||
pass
|
|
||||||
elif not self.impl_is_multi():
|
|
||||||
val = value
|
|
||||||
do_validation(val, None)
|
|
||||||
elif self.impl_is_submulti():
|
|
||||||
if not isinstance(value, list):
|
|
||||||
raise ValueError(_('which must be a list'))
|
|
||||||
for err_index, lval in enumerate(value):
|
|
||||||
if isinstance(lval, Calculation):
|
|
||||||
continue
|
|
||||||
if not isinstance(lval, list):
|
|
||||||
raise ValueError(_('which "{}" must be a list of list'
|
|
||||||
'').format(lval))
|
|
||||||
for val in lval:
|
|
||||||
if isinstance(val, Calculation):
|
|
||||||
continue
|
|
||||||
do_validation(val,
|
|
||||||
err_index)
|
|
||||||
else:
|
|
||||||
# it's a multi
|
|
||||||
if not isinstance(value, list):
|
|
||||||
raise ValueError(_('which must be a list'))
|
|
||||||
for err_index, val in enumerate(value):
|
|
||||||
if isinstance(val, Calculation):
|
|
||||||
continue
|
|
||||||
do_validation(val,
|
|
||||||
err_index)
|
|
||||||
except ValueError as err:
|
|
||||||
raise ValueOptionError(value,
|
|
||||||
self._display_name,
|
|
||||||
option_bag.ori_option,
|
|
||||||
'{0}'.format(err),
|
|
||||||
err_index)
|
|
||||||
|
|
||||||
def impl_validate(self,
|
def impl_validate(self,
|
||||||
value: Any,
|
value: Any,
|
||||||
option_bag: OptionBag,
|
option_bag: OptionBag,
|
||||||
check_error: bool=True) -> None:
|
check_error: bool=True,
|
||||||
|
loaded: bool=False,
|
||||||
|
) -> None:
|
||||||
"""Return True if value is really valid
|
"""Return True if value is really valid
|
||||||
If not validate or invalid return it returns False
|
If not validate or invalid return it returns False
|
||||||
"""
|
"""
|
||||||
|
@ -337,7 +282,6 @@ class Option(BaseOption):
|
||||||
not 'validator' in config_bag.properties:
|
not 'validator' in config_bag.properties:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _is_not_unique(value, option_bag):
|
def _is_not_unique(value, option_bag):
|
||||||
# if set(value) has not same length than value
|
# if set(value) has not same length than value
|
||||||
if config_bag is undefined or not check_error or \
|
if config_bag is undefined or not check_error or \
|
||||||
|
@ -353,9 +297,11 @@ class Option(BaseOption):
|
||||||
'').format(val))
|
'').format(val))
|
||||||
|
|
||||||
def calculation_validator(val,
|
def calculation_validator(val,
|
||||||
_index):
|
_index,
|
||||||
|
):
|
||||||
for validator in getattr(self, '_validators', []):
|
for validator in getattr(self, '_validators', []):
|
||||||
calc_is_warnings_only = hasattr(validator, 'warnings_only') and validator.warnings_only
|
calc_is_warnings_only = hasattr(validator, 'warnings_only') and \
|
||||||
|
validator.warnings_only
|
||||||
if ((check_error and not calc_is_warnings_only) or
|
if ((check_error and not calc_is_warnings_only) or
|
||||||
(not check_error and calc_is_warnings_only)):
|
(not check_error and calc_is_warnings_only)):
|
||||||
try:
|
try:
|
||||||
|
@ -374,26 +320,32 @@ class Option(BaseOption):
|
||||||
**kwargs)
|
**kwargs)
|
||||||
except ValueWarning as warn:
|
except ValueWarning as warn:
|
||||||
warnings.warn_explicit(ValueWarning(val,
|
warnings.warn_explicit(ValueWarning(val,
|
||||||
self._display_name,
|
self.get_type(),
|
||||||
self,
|
self,
|
||||||
'{0}'.format(warn),
|
str(warn),
|
||||||
_index),
|
_index),
|
||||||
ValueWarning,
|
ValueWarning,
|
||||||
self.__class__.__name__, 356)
|
self.__class__.__name__, 319)
|
||||||
|
|
||||||
def do_validation(_value,
|
def do_validation(_value,
|
||||||
_index):
|
_index,
|
||||||
|
):
|
||||||
|
#
|
||||||
if isinstance(_value, list):
|
if isinstance(_value, list):
|
||||||
raise ValueError(_('which must not be a list').format(_value,
|
raise ValueError(_('which must not be a list').format(_value,
|
||||||
self.impl_get_display_name()))
|
self.impl_get_display_name()),
|
||||||
|
)
|
||||||
if isinstance(_value, Calculation) and config_bag is undefined:
|
if isinstance(_value, Calculation) and config_bag is undefined:
|
||||||
return False
|
return
|
||||||
|
|
||||||
if _value is not None:
|
if _value is not None:
|
||||||
if check_error:
|
if check_error:
|
||||||
# option validation
|
# option validation
|
||||||
self.validate(_value)
|
self.validate(_value)
|
||||||
self.validate_with_option(_value,
|
self.validate_with_option(_value,
|
||||||
option_bag)
|
option_bag,
|
||||||
|
loaded=loaded,
|
||||||
|
)
|
||||||
if ((check_error and not is_warnings_only) or
|
if ((check_error and not is_warnings_only) or
|
||||||
(not check_error and is_warnings_only)):
|
(not check_error and is_warnings_only)):
|
||||||
try:
|
try:
|
||||||
|
@ -402,16 +354,18 @@ class Option(BaseOption):
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
if is_warnings_only:
|
if is_warnings_only:
|
||||||
warnings.warn_explicit(ValueWarning(_value,
|
warnings.warn_explicit(ValueWarning(_value,
|
||||||
self._display_name,
|
self.get_type(),
|
||||||
self,
|
self,
|
||||||
'{0}'.format(err),
|
str(err),
|
||||||
_index),
|
_index),
|
||||||
ValueWarning,
|
ValueWarning,
|
||||||
self.__class__.__name__, 0)
|
self.__class__.__name__, 0)
|
||||||
else:
|
else:
|
||||||
raise err
|
raise err
|
||||||
calculation_validator(_value,
|
if not loaded:
|
||||||
_index)
|
calculation_validator(_value,
|
||||||
|
_index,
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
val = value
|
val = value
|
||||||
err_index = force_index
|
err_index = force_index
|
||||||
|
@ -423,11 +377,15 @@ class Option(BaseOption):
|
||||||
raise ValueError(_('which must be a list'))
|
raise ValueError(_('which must be a list'))
|
||||||
for val in value:
|
for val in value:
|
||||||
do_validation(val,
|
do_validation(val,
|
||||||
force_index)
|
force_index,
|
||||||
_is_not_unique(value, option_bag)
|
)
|
||||||
|
_is_not_unique(value,
|
||||||
|
option_bag,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
do_validation(val,
|
do_validation(val,
|
||||||
force_index)
|
force_index,
|
||||||
|
)
|
||||||
elif isinstance(value, Calculation) and config_bag is undefined:
|
elif isinstance(value, Calculation) and config_bag is undefined:
|
||||||
pass
|
pass
|
||||||
elif not isinstance(value, list):
|
elif not isinstance(value, list):
|
||||||
|
@ -444,73 +402,68 @@ class Option(BaseOption):
|
||||||
err_index)
|
err_index)
|
||||||
_is_not_unique(lval, option_bag)
|
_is_not_unique(lval, option_bag)
|
||||||
else:
|
else:
|
||||||
# FIXME subtimal, not several time is whole=True!
|
# FIXME suboptimal, not several time is whole=True!
|
||||||
for err_index, val in enumerate(value):
|
for err_index, val in enumerate(value):
|
||||||
do_validation(val,
|
do_validation(val,
|
||||||
err_index)
|
err_index,
|
||||||
|
)
|
||||||
_is_not_unique(value, option_bag)
|
_is_not_unique(value, option_bag)
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
if config_bag is undefined or \
|
if config_bag is undefined or \
|
||||||
'demoting_error_warning' not in config_bag.properties:
|
'demoting_error_warning' not in config_bag.properties:
|
||||||
raise ValueOptionError(val,
|
raise ValueOptionError(val,
|
||||||
self._display_name,
|
self.get_type(),
|
||||||
option_bag.ori_option,
|
option_bag.ori_option,
|
||||||
'{0}'.format(err),
|
str(err),
|
||||||
err_index) from err
|
err_index) from err
|
||||||
warnings.warn_explicit(ValueErrorWarning(val,
|
warnings.warn_explicit(ValueErrorWarning(val,
|
||||||
self._display_name,
|
self.get_type(),
|
||||||
option_bag.ori_option,
|
option_bag.ori_option,
|
||||||
'{0}'.format(err),
|
str(err),
|
||||||
err_index),
|
err_index),
|
||||||
ValueErrorWarning,
|
ValueErrorWarning,
|
||||||
self.__class__.__name__, 0)
|
self.__class__.__name__, 0)
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _validate_calculator(self,
|
|
||||||
callback: Callable,
|
|
||||||
callback_params: Optional[Params]=None) -> None:
|
|
||||||
if callback is None:
|
|
||||||
return
|
|
||||||
default_multi = getattr(self, '_default_multi', None)
|
|
||||||
is_multi = self.impl_is_multi()
|
|
||||||
default = self.impl_getdefault()
|
|
||||||
if (not is_multi and (default is not None or default_multi is not None)) or \
|
|
||||||
(is_multi and (default != [] or default_multi is not None)):
|
|
||||||
raise ValueError(_('default value not allowed if option "{0}" '
|
|
||||||
'is calculated').format(self.impl_getname()))
|
|
||||||
|
|
||||||
def sync_validate_with_option(self,
|
|
||||||
value: Any,
|
|
||||||
option_bag: OptionBag) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def validate_with_option(self,
|
def validate_with_option(self,
|
||||||
value: Any,
|
value: Any,
|
||||||
option_bag: OptionBag) -> None:
|
option_bag: OptionBag,
|
||||||
pass
|
loaded: bool,
|
||||||
|
) -> None:
|
||||||
|
"""validation function with option
|
||||||
|
"""
|
||||||
|
|
||||||
def second_level_validation(self,
|
def second_level_validation(self,
|
||||||
value: Any,
|
value: Any,
|
||||||
warnings_only: bool) -> None:
|
warnings_only: bool,
|
||||||
pass
|
) -> None:
|
||||||
|
"""less import validation function
|
||||||
|
"""
|
||||||
|
|
||||||
def impl_is_leader(self):
|
def impl_is_leader(self):
|
||||||
|
"""check if option is a leader in a leadership
|
||||||
|
"""
|
||||||
leadership = self.impl_get_leadership()
|
leadership = self.impl_get_leadership()
|
||||||
if leadership is None:
|
if leadership is None:
|
||||||
return False
|
return False
|
||||||
return leadership.is_leader(self)
|
return leadership.is_leader(self)
|
||||||
|
|
||||||
def impl_is_follower(self):
|
def impl_is_follower(self):
|
||||||
|
"""check if option is a leader in a follower
|
||||||
|
"""
|
||||||
leadership = self.impl_get_leadership()
|
leadership = self.impl_get_leadership()
|
||||||
if leadership is None:
|
if leadership is None:
|
||||||
return False
|
return False
|
||||||
return not leadership.is_leader(self)
|
return not leadership.is_leader(self)
|
||||||
|
|
||||||
def impl_get_leadership(self):
|
def impl_get_leadership(self):
|
||||||
|
"""get leadership
|
||||||
|
"""
|
||||||
leadership = getattr(self, '_leadership', None)
|
leadership = getattr(self, '_leadership', None)
|
||||||
if leadership is None:
|
if leadership is None:
|
||||||
return leadership
|
return leadership
|
||||||
|
#pylint: disable=not-callable
|
||||||
return leadership()
|
return leadership()
|
||||||
|
|
||||||
def to_dynoption(self,
|
def to_dynoption(self,
|
||||||
|
@ -518,8 +471,14 @@ class Option(BaseOption):
|
||||||
suffix: str,
|
suffix: str,
|
||||||
dyn_parent,
|
dyn_parent,
|
||||||
) -> SynDynOption:
|
) -> SynDynOption:
|
||||||
|
"""tranforme a dynoption to a syndynoption
|
||||||
|
"""
|
||||||
return SynDynOption(self,
|
return SynDynOption(self,
|
||||||
rootpath,
|
rootpath,
|
||||||
suffix,
|
suffix,
|
||||||
dyn_parent,
|
dyn_parent,
|
||||||
)
|
)
|
||||||
|
def validate(self, value: Any):
|
||||||
|
"""option needs a validate function
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
|
@ -18,27 +18,31 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
from copy import copy
|
"""OptionDescription
|
||||||
|
"""
|
||||||
from typing import Optional, Iterator, Union, List
|
from typing import Optional, Iterator, Union, List
|
||||||
|
|
||||||
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from ..setting import ConfigBag, OptionBag, groups, undefined, owners, Undefined
|
from ..setting import ConfigBag, OptionBag, groups, undefined, owners, Undefined
|
||||||
from .baseoption import BaseOption
|
from .baseoption import BaseOption
|
||||||
from .syndynoptiondescription import SynDynOptionDescription, SynDynLeadership
|
from .syndynoptiondescription import SynDynOptionDescription
|
||||||
from ..error import ConfigError, ConflictError
|
from ..error import ConfigError, ConflictError
|
||||||
|
|
||||||
|
|
||||||
class CacheOptionDescription(BaseOption):
|
class CacheOptionDescription(BaseOption):
|
||||||
|
"""manage cache for option description
|
||||||
|
"""
|
||||||
__slots__ = ('_cache_force_store_values',
|
__slots__ = ('_cache_force_store_values',
|
||||||
'_cache_dependencies_information',
|
'_cache_dependencies_information',
|
||||||
)
|
)
|
||||||
|
|
||||||
def impl_already_build_caches(self) -> bool:
|
def impl_already_build_caches(self) -> bool:
|
||||||
|
"""is a readonly option?
|
||||||
|
"""
|
||||||
return self.impl_is_readonly()
|
return self.impl_is_readonly()
|
||||||
|
|
||||||
def _build_cache(self,
|
def _build_cache(self,
|
||||||
path='',
|
|
||||||
_consistencies=None,
|
_consistencies=None,
|
||||||
_consistencies_id=0,
|
_consistencies_id=0,
|
||||||
currpath: List[str]=None,
|
currpath: List[str]=None,
|
||||||
|
@ -49,6 +53,7 @@ class CacheOptionDescription(BaseOption):
|
||||||
) -> None:
|
) -> None:
|
||||||
"""validate options and set option has readonly option
|
"""validate options and set option has readonly option
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=too-many-branches,too-many-arguments
|
||||||
# _consistencies is None only when we start to build cache
|
# _consistencies is None only when we start to build cache
|
||||||
if _consistencies is None:
|
if _consistencies is None:
|
||||||
init = True
|
init = True
|
||||||
|
@ -65,15 +70,16 @@ class CacheOptionDescription(BaseOption):
|
||||||
# cache already set
|
# cache already set
|
||||||
raise ConfigError(_('option description seems to be part of an other '
|
raise ConfigError(_('option description seems to be part of an other '
|
||||||
'config'))
|
'config'))
|
||||||
for option in self.get_children(config_bag=undefined,
|
for option in self.get_children(config_bag=undefined, # pylint: disable=no-member
|
||||||
dyn=False):
|
dyn=False,
|
||||||
|
):
|
||||||
if __debug__:
|
if __debug__:
|
||||||
cache_option.append(option)
|
cache_option.append(option)
|
||||||
sub_currpath = currpath + [option.impl_getname()]
|
sub_currpath = currpath + [option.impl_getname()]
|
||||||
subpath = '.'.join(sub_currpath)
|
subpath = '.'.join(sub_currpath)
|
||||||
if isinstance(option, OptionDescription):
|
if isinstance(option, OptionDescription):
|
||||||
option._build_cache(subpath,
|
# pylint: disable=protected-access
|
||||||
_consistencies,
|
option._build_cache(_consistencies,
|
||||||
_consistencies_id,
|
_consistencies_id,
|
||||||
sub_currpath,
|
sub_currpath,
|
||||||
cache_option,
|
cache_option,
|
||||||
|
@ -84,7 +90,6 @@ class CacheOptionDescription(BaseOption):
|
||||||
else:
|
else:
|
||||||
for information in option.get_dependencies_information():
|
for information in option.get_dependencies_information():
|
||||||
dependencies_information.setdefault(information, []).append(option)
|
dependencies_information.setdefault(information, []).append(option)
|
||||||
is_multi = option.impl_is_multi()
|
|
||||||
if not option.impl_is_symlinkoption():
|
if not option.impl_is_symlinkoption():
|
||||||
properties = option.impl_getproperties()
|
properties = option.impl_getproperties()
|
||||||
if 'force_store_value' in properties:
|
if 'force_store_value' in properties:
|
||||||
|
@ -101,18 +106,21 @@ class CacheOptionDescription(BaseOption):
|
||||||
if option.impl_is_readonly():
|
if option.impl_is_readonly():
|
||||||
raise ConflictError(_('duplicate option: {0}').format(option))
|
raise ConflictError(_('duplicate option: {0}').format(option))
|
||||||
if not self.impl_is_readonly() and display_name:
|
if not self.impl_is_readonly() and display_name:
|
||||||
option._display_name_function = display_name
|
option._display_name_function = display_name # pylint: disable=protected-access
|
||||||
option._path = subpath
|
option._path = subpath # pylint: disable=protected-access
|
||||||
option._set_readonly()
|
option._set_readonly() # pylint: disable=protected-access
|
||||||
if init:
|
if init:
|
||||||
self._cache_force_store_values = force_store_values
|
self._cache_force_store_values = force_store_values # pylint: disable=attribute-defined-outside-init
|
||||||
self._cache_dependencies_information = dependencies_information
|
self._cache_dependencies_information = dependencies_information # pylint: disable=attribute-defined-outside-init
|
||||||
self._path = self._name
|
self._path = self._name # pylint: disable=attribute-defined-outside-init,no-member
|
||||||
self._set_readonly()
|
self._set_readonly()
|
||||||
|
|
||||||
def impl_build_force_store_values(self,
|
def impl_build_force_store_values(self,
|
||||||
config_bag: ConfigBag,
|
config_bag: ConfigBag,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
"""set value to force_store_values option
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-many-branches
|
||||||
def do_option_bags(option):
|
def do_option_bags(option):
|
||||||
if option.issubdyn():
|
if option.issubdyn():
|
||||||
dynopt = option.getsubdyn()
|
dynopt = option.getsubdyn()
|
||||||
|
@ -146,7 +154,7 @@ class CacheOptionDescription(BaseOption):
|
||||||
leader = option.impl_get_leadership().get_leader()
|
leader = option.impl_get_leadership().get_leader()
|
||||||
for leader_option_bag in do_option_bags(leader):
|
for leader_option_bag in do_option_bags(leader):
|
||||||
leader_option_bag.properties = frozenset()
|
leader_option_bag.properties = frozenset()
|
||||||
follower_len = len(values.getvalue(leader_option_bag))
|
follower_len = len(values.get_value(leader_option_bag))
|
||||||
if option.issubdyn():
|
if option.issubdyn():
|
||||||
subpath = leader_option_bag.option.rootpath
|
subpath = leader_option_bag.option.rootpath
|
||||||
doption = option.to_dynoption(subpath,
|
doption = option.to_dynoption(subpath,
|
||||||
|
@ -164,7 +172,7 @@ class CacheOptionDescription(BaseOption):
|
||||||
config_bag,
|
config_bag,
|
||||||
properties=frozenset(),
|
properties=frozenset(),
|
||||||
)
|
)
|
||||||
value = values.getvalue(option_bag)
|
value = values.get_value(option_bag)
|
||||||
if value is None:
|
if value is None:
|
||||||
continue
|
continue
|
||||||
values.set_storage_value(subpath,
|
values.set_storage_value(subpath,
|
||||||
|
@ -175,7 +183,7 @@ class CacheOptionDescription(BaseOption):
|
||||||
else:
|
else:
|
||||||
for option_bag in do_option_bags(option):
|
for option_bag in do_option_bags(option):
|
||||||
option_bag.properties = frozenset()
|
option_bag.properties = frozenset()
|
||||||
value = values.getvalue(option_bag)
|
value = values.get_value(option_bag)
|
||||||
if value is None:
|
if value is None:
|
||||||
continue
|
continue
|
||||||
if values.hasvalue(option_bag.option.impl_getpath()):
|
if values.hasvalue(option_bag.option.impl_getpath()):
|
||||||
|
@ -188,6 +196,8 @@ class CacheOptionDescription(BaseOption):
|
||||||
|
|
||||||
|
|
||||||
class OptionDescriptionWalk(CacheOptionDescription):
|
class OptionDescriptionWalk(CacheOptionDescription):
|
||||||
|
"""get child of option description
|
||||||
|
"""
|
||||||
__slots__ = ('_children',)
|
__slots__ = ('_children',)
|
||||||
|
|
||||||
def get_child(self,
|
def get_child(self,
|
||||||
|
@ -195,16 +205,18 @@ class OptionDescriptionWalk(CacheOptionDescription):
|
||||||
config_bag: ConfigBag,
|
config_bag: ConfigBag,
|
||||||
subpath: str,
|
subpath: str,
|
||||||
) -> Union[BaseOption, SynDynOptionDescription]:
|
) -> Union[BaseOption, SynDynOptionDescription]:
|
||||||
|
"""get a child
|
||||||
|
"""
|
||||||
# if not dyn
|
# if not dyn
|
||||||
if name in self._children[0]:
|
if name in self._children[0]: # pylint: disable=no-member
|
||||||
option = self._children[1][self._children[0].index(name)]
|
option = self._children[1][self._children[0].index(name)] # pylint: disable=no-member
|
||||||
if option.issubdyn():
|
if option.issubdyn():
|
||||||
raise AttributeError(_(f'unknown option "{name}" '
|
raise AttributeError(_(f'unknown option "{name}" '
|
||||||
"in root optiondescription (it's a dynamic option)"
|
"in root optiondescription (it's a dynamic option)"
|
||||||
))
|
))
|
||||||
return option
|
return option
|
||||||
# if dyn
|
# if dyn
|
||||||
for child in self._children[1]:
|
for child in self._children[1]: # pylint: disable=no-member
|
||||||
if not child.impl_is_dynoptiondescription():
|
if not child.impl_is_dynoptiondescription():
|
||||||
continue
|
continue
|
||||||
cname = child.impl_getname()
|
cname = child.impl_getname()
|
||||||
|
@ -217,7 +229,7 @@ class OptionDescriptionWalk(CacheOptionDescription):
|
||||||
suffix,
|
suffix,
|
||||||
child,
|
child,
|
||||||
)
|
)
|
||||||
if self.impl_get_group_type() == groups.root:
|
if self.impl_get_group_type() == groups.root: # pylint: disable=no-member
|
||||||
raise AttributeError(_(f'unknown option "{name}" '
|
raise AttributeError(_(f'unknown option "{name}" '
|
||||||
'in root optiondescription'
|
'in root optiondescription'
|
||||||
))
|
))
|
||||||
|
@ -229,21 +241,22 @@ class OptionDescriptionWalk(CacheOptionDescription):
|
||||||
config_bag: Union[ConfigBag, Undefined],
|
config_bag: Union[ConfigBag, Undefined],
|
||||||
dyn: bool=True,
|
dyn: bool=True,
|
||||||
) -> Union[BaseOption, SynDynOptionDescription]:
|
) -> Union[BaseOption, SynDynOptionDescription]:
|
||||||
|
"""get children
|
||||||
|
"""
|
||||||
if not dyn or config_bag is undefined or \
|
if not dyn or config_bag is undefined or \
|
||||||
config_bag.context.get_description() == self:
|
config_bag.context.get_description() == self:
|
||||||
subpath = ''
|
subpath = ''
|
||||||
else:
|
else:
|
||||||
subpath = self.impl_getpath()
|
subpath = self.impl_getpath()
|
||||||
children = []
|
for child in self._children[1]: # pylint: disable=no-member
|
||||||
for child in self._children[1]:
|
|
||||||
if dyn and child.impl_is_dynoptiondescription():
|
if dyn and child.impl_is_dynoptiondescription():
|
||||||
for suffix in child.get_suffixes(config_bag):
|
for suffix in child.get_suffixes(config_bag):
|
||||||
children.append(child.to_dynoption(subpath,
|
yield child.to_dynoption(subpath,
|
||||||
suffix,
|
suffix,
|
||||||
child))
|
child,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
children.append(child)
|
yield child
|
||||||
return children
|
|
||||||
|
|
||||||
def get_children_recursively(self,
|
def get_children_recursively(self,
|
||||||
bytype: Optional[BaseOption],
|
bytype: Optional[BaseOption],
|
||||||
|
@ -251,6 +264,8 @@ class OptionDescriptionWalk(CacheOptionDescription):
|
||||||
config_bag: ConfigBag,
|
config_bag: ConfigBag,
|
||||||
self_opt: BaseOption=None,
|
self_opt: BaseOption=None,
|
||||||
) -> Iterator[Union[BaseOption, SynDynOptionDescription]]:
|
) -> Iterator[Union[BaseOption, SynDynOptionDescription]]:
|
||||||
|
"""get children recursively
|
||||||
|
"""
|
||||||
if self_opt is None:
|
if self_opt is None:
|
||||||
self_opt = self
|
self_opt = self
|
||||||
for option in self_opt.get_children(config_bag):
|
for option in self_opt.get_children(config_bag):
|
||||||
|
@ -308,8 +323,8 @@ class OptionDescription(OptionDescriptionWalk):
|
||||||
if dynopt_names:
|
if dynopt_names:
|
||||||
for dynopt in dynopt_names:
|
for dynopt in dynopt_names:
|
||||||
if child != dynopt and child.startswith(dynopt):
|
if child != dynopt and child.startswith(dynopt):
|
||||||
raise ConflictError(_('the option\'s name "{}" start as '
|
raise ConflictError(_(f'the option\'s name "{child}" start as '
|
||||||
'the dynoptiondescription\'s name "{}"').format(child, dynopt))
|
f'the dynoptiondescription\'s name "{dynopt}"'))
|
||||||
old = child
|
old = child
|
||||||
self._children = children_
|
self._children = children_
|
||||||
# the group_type is useful for filtering OptionDescriptions in a config
|
# the group_type is useful for filtering OptionDescriptions in a config
|
||||||
|
@ -322,17 +337,24 @@ class OptionDescription(OptionDescriptionWalk):
|
||||||
'dynoptiondescription'))
|
'dynoptiondescription'))
|
||||||
|
|
||||||
def impl_is_optiondescription(self) -> bool:
|
def impl_is_optiondescription(self) -> bool:
|
||||||
|
"""the option is an option description
|
||||||
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def impl_is_dynoptiondescription(self) -> bool:
|
def impl_is_dynoptiondescription(self) -> bool:
|
||||||
|
"""the option is not dynamic
|
||||||
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def impl_is_leadership(self) -> bool:
|
def impl_is_leadership(self) -> bool:
|
||||||
|
"""the option is not a leadership
|
||||||
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
def impl_set_group_type(self,
|
def impl_set_group_type(self,
|
||||||
group_type: groups.GroupType) -> None:
|
group_type: groups.GroupType,
|
||||||
|
) -> None:
|
||||||
"""sets a given group object to an OptionDescription
|
"""sets a given group object to an OptionDescription
|
||||||
|
|
||||||
:param group_type: an instance of `GroupType` or `LeadershipGroupType`
|
:param group_type: an instance of `GroupType` or `LeadershipGroupType`
|
||||||
|
@ -351,16 +373,22 @@ class OptionDescription(OptionDescriptionWalk):
|
||||||
self._group_type = group_type
|
self._group_type = group_type
|
||||||
|
|
||||||
def impl_get_group_type(self) -> groups.GroupType:
|
def impl_get_group_type(self) -> groups.GroupType:
|
||||||
|
"""get the group type of option description
|
||||||
|
"""
|
||||||
return self._group_type
|
return self._group_type
|
||||||
|
|
||||||
def to_dynoption(self,
|
def to_dynoption(self,
|
||||||
rootpath: str,
|
rootpath: str,
|
||||||
suffix: str,
|
suffix: str,
|
||||||
ori_dyn) -> SynDynOptionDescription:
|
ori_dyn) -> SynDynOptionDescription:
|
||||||
|
"""get syn dyn option description
|
||||||
|
"""
|
||||||
return SynDynOptionDescription(self,
|
return SynDynOptionDescription(self,
|
||||||
rootpath,
|
rootpath,
|
||||||
suffix,
|
suffix,
|
||||||
ori_dyn)
|
ori_dyn)
|
||||||
|
|
||||||
def impl_is_dynsymlinkoption(self) -> bool:
|
def impl_is_dynsymlinkoption(self) -> bool:
|
||||||
|
"""option is not a dyn symlink option
|
||||||
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -18,15 +18,15 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""PasswordOption
|
||||||
|
"""
|
||||||
|
|
||||||
from ..setting import undefined, Undefined, OptionBag
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .option import Option
|
|
||||||
from .stroption import StrOption
|
from .stroption import StrOption
|
||||||
|
|
||||||
|
|
||||||
class PasswordOption(StrOption):
|
class PasswordOption(StrOption):
|
||||||
"represents the choice of a password"
|
"""represents the choice of a password
|
||||||
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'password'
|
_type = _('password')
|
||||||
_display_name = _('password')
|
|
||||||
|
|
|
@ -18,12 +18,11 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""PermissionsOption
|
||||||
|
"""
|
||||||
import re
|
import re
|
||||||
import sys
|
|
||||||
|
|
||||||
from ..setting import undefined, Undefined, OptionBag
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .option import Option
|
|
||||||
from .intoption import IntOption
|
from .intoption import IntOption
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,8 +35,7 @@ class PermissionsOption(IntOption):
|
||||||
"""
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
perm_re = re.compile(r"^[0-7]{3,4}$")
|
perm_re = re.compile(r"^[0-7]{3,4}$")
|
||||||
_type = 'permissions'
|
_type = _('unix file permissions')
|
||||||
_display_name = _('unix file permissions')
|
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
*args,
|
*args,
|
||||||
|
@ -72,4 +70,4 @@ class PermissionsOption(IntOption):
|
||||||
raise ValueError(_(f'{new} has more right than {old}'))
|
raise ValueError(_(f'{new} has more right than {old}'))
|
||||||
old_digit = new_digit
|
old_digit = new_digit
|
||||||
if str_value == '777':
|
if str_value == '777':
|
||||||
raise ValueError(_(f'too weak'))
|
raise ValueError(_('too weak'))
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""PortOption
|
||||||
|
"""
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
|
@ -36,8 +38,7 @@ class PortOption(StrOption):
|
||||||
"""
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
port_re = re.compile(r"^[0-9]*$")
|
port_re = re.compile(r"^[0-9]*$")
|
||||||
_type = 'port'
|
_port = _('port')
|
||||||
_display_name = _('port')
|
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
*args,
|
*args,
|
||||||
|
@ -81,7 +82,8 @@ class PortOption(StrOption):
|
||||||
def validate(self,
|
def validate(self,
|
||||||
value: str) -> None:
|
value: str) -> None:
|
||||||
super().validate(value)
|
super().validate(value)
|
||||||
if self.impl_get_extra('_allow_protocol') and (value.startswith('tcp:') or value.startswith('udp:')):
|
if self.impl_get_extra('_allow_protocol') and (value.startswith('tcp:') or
|
||||||
|
value.startswith('udp:')):
|
||||||
value = [value[4:]]
|
value = [value[4:]]
|
||||||
elif self.impl_get_extra('_allow_range') and ":" in str(value):
|
elif self.impl_get_extra('_allow_range') and ":" in str(value):
|
||||||
value = value.split(':')
|
value = value.split(':')
|
||||||
|
@ -100,7 +102,8 @@ class PortOption(StrOption):
|
||||||
def second_level_validation(self,
|
def second_level_validation(self,
|
||||||
value: str,
|
value: str,
|
||||||
warnings_only: bool) -> None:
|
warnings_only: bool) -> None:
|
||||||
if self.impl_get_extra('_allow_protocol') and (value.startswith('tcp:') or value.startswith('udp:')):
|
if self.impl_get_extra('_allow_protocol') and (value.startswith('tcp:') or
|
||||||
|
value.startswith('udp:')):
|
||||||
value = [value[4:]]
|
value = [value[4:]]
|
||||||
elif ':' in value:
|
elif ':' in value:
|
||||||
value = value.split(':')
|
value = value.split(':')
|
||||||
|
|
|
@ -18,31 +18,40 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
import sys
|
"""StrOption and RegexpOption
|
||||||
|
"""
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from ..setting import undefined, Undefined, OptionBag
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .option import Option
|
from .option import Option
|
||||||
|
|
||||||
|
|
||||||
class StrOption(Option):
|
class StrOption(Option):
|
||||||
"represents the choice of a string"
|
"""represents a string
|
||||||
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'string'
|
_type = _('string')
|
||||||
_display_name = _('string')
|
|
||||||
|
|
||||||
def validate(self,
|
def validate(self,
|
||||||
value: str) -> None:
|
value: str,
|
||||||
|
) -> None:
|
||||||
|
"""validation
|
||||||
|
"""
|
||||||
if not isinstance(value, str):
|
if not isinstance(value, str):
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
|
|
||||||
|
|
||||||
class RegexpOption(StrOption):
|
class RegexpOption(StrOption):
|
||||||
|
"""regexp validation, this is base option use to do a custom's one
|
||||||
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
|
|
||||||
def validate(self,
|
def validate(self,
|
||||||
value: Any) -> None:
|
value: Any,
|
||||||
|
) -> None:
|
||||||
|
# pylint: disable=no-member
|
||||||
|
"""validation
|
||||||
|
"""
|
||||||
super().validate(value)
|
super().validate(value)
|
||||||
match = self._regexp.search(value)
|
match = self._regexp.search(value)
|
||||||
if not match:
|
if not match:
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""SymLinkOption link to an other option
|
||||||
|
"""
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from .baseoption import BaseOption, valid_name
|
from .baseoption import BaseOption, valid_name
|
||||||
from ..error import ConfigError
|
from ..error import ConfigError
|
||||||
|
@ -25,11 +27,15 @@ from ..i18n import _
|
||||||
|
|
||||||
|
|
||||||
class SymLinkOption(BaseOption):
|
class SymLinkOption(BaseOption):
|
||||||
|
"""SymLinkOption link to an other option
|
||||||
|
"""
|
||||||
__slots__ = ('_opt',)
|
__slots__ = ('_opt',)
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
name: str,
|
name: str,
|
||||||
opt: BaseOption) -> None:
|
opt: BaseOption,
|
||||||
|
) -> None:
|
||||||
|
# pylint: disable=super-init-not-called
|
||||||
if not valid_name(name):
|
if not valid_name(name):
|
||||||
raise ValueError(_('"{0}" is an invalid name for an option').format(name))
|
raise ValueError(_('"{0}" is an invalid name for an option').format(name))
|
||||||
if not isinstance(opt, BaseOption) or \
|
if not isinstance(opt, BaseOption) or \
|
||||||
|
@ -55,27 +61,36 @@ class SymLinkOption(BaseOption):
|
||||||
'dynoptiondescription'))
|
'dynoptiondescription'))
|
||||||
|
|
||||||
def impl_has_dependency(self,
|
def impl_has_dependency(self,
|
||||||
self_is_dep: bool=True) -> bool:
|
self_is_dep: bool=True,
|
||||||
|
) -> bool:
|
||||||
"""If self_is_dep is True, it has dependency (self._opt), so return True
|
"""If self_is_dep is True, it has dependency (self._opt), so return True
|
||||||
if self_is_dep is False, cannot has validation or callback, so return False
|
if self_is_dep is False, cannot has validation or callback, so return False
|
||||||
"""
|
"""
|
||||||
return self_is_dep
|
return self_is_dep
|
||||||
|
|
||||||
def impl_is_symlinkoption(self) -> bool:
|
def impl_is_symlinkoption(self) -> bool:
|
||||||
|
"""it's a symlinkoption
|
||||||
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def impl_getopt(self) -> BaseOption:
|
def impl_getopt(self) -> BaseOption:
|
||||||
|
"""get to linked option
|
||||||
|
"""
|
||||||
return self._opt
|
return self._opt
|
||||||
|
|
||||||
def issubdyn(self) -> bool:
|
def issubdyn(self) -> bool:
|
||||||
|
"""it's not a sub dyn option
|
||||||
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def impl_is_multi(self) -> bool:
|
def impl_is_multi(self) -> bool:
|
||||||
|
"""is it a multi?
|
||||||
|
"""
|
||||||
if self._opt.issubdyn():
|
if self._opt.issubdyn():
|
||||||
return True
|
return True
|
||||||
return self._opt.impl_is_multi()
|
return self._opt.impl_is_multi()
|
||||||
|
|
||||||
def impl_is_submulti(self) -> bool:
|
def impl_is_submulti(self) -> bool:
|
||||||
if self._opt.issubdyn() and self._opt.impl_is_multi():
|
"""is it a submulti?
|
||||||
return True
|
"""
|
||||||
return self._opt.impl_is_submulti()
|
return self._opt.impl_is_submulti()
|
||||||
|
|
|
@ -18,8 +18,9 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""SynDynOption internal option, it's an instanciate synoption
|
||||||
|
"""
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from ..setting import undefined, OptionBag
|
|
||||||
from .baseoption import BaseOption
|
from .baseoption import BaseOption
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,35 +50,40 @@ class SynDynOption:
|
||||||
name,
|
name,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __eq__(self,
|
|
||||||
left: BaseOption) -> bool:
|
|
||||||
if not isinstance(left, SynDynOption):
|
|
||||||
return False
|
|
||||||
return self.opt == left.opt and \
|
|
||||||
self.rootpath == left.rootpath and \
|
|
||||||
self.suffix == left.suffix
|
|
||||||
|
|
||||||
def impl_getname(self) -> str:
|
def impl_getname(self) -> str:
|
||||||
|
"""get option name
|
||||||
|
"""
|
||||||
return self.opt.impl_getname() + self.dyn_parent.convert_suffix_to_path(self.suffix)
|
return self.opt.impl_getname() + self.dyn_parent.convert_suffix_to_path(self.suffix)
|
||||||
|
|
||||||
def impl_get_display_name(self) -> str:
|
def impl_get_display_name(self) -> str:
|
||||||
return self.opt._get_display_name(dyn_name=self.impl_getname(),
|
"""get option display name
|
||||||
suffix=self.dyn_parent.convert_suffix_to_path(self.suffix),
|
"""
|
||||||
|
suffix = self.dyn_parent.convert_suffix_to_path(self.suffix)
|
||||||
|
return self.opt._get_display_name(dyn_name=self.impl_getname(), # pylint: disable=protected-access
|
||||||
|
suffix=suffix,
|
||||||
)
|
)
|
||||||
|
|
||||||
def impl_getsuffix(self) -> str:
|
def impl_getsuffix(self) -> str:
|
||||||
|
"""get suffix
|
||||||
|
"""
|
||||||
return self.suffix
|
return self.suffix
|
||||||
|
|
||||||
def impl_getpath(self) -> str:
|
def impl_getpath(self) -> str:
|
||||||
|
"""get path
|
||||||
|
"""
|
||||||
path = self.impl_getname()
|
path = self.impl_getname()
|
||||||
if self.rootpath:
|
if self.rootpath:
|
||||||
path = f'{self.rootpath}.{path}'
|
path = f'{self.rootpath}.{path}'
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def impl_is_dynsymlinkoption(self) -> bool:
|
def impl_is_dynsymlinkoption(self) -> bool:
|
||||||
|
"""it's a dynsymlinkoption
|
||||||
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def impl_get_leadership(self):
|
def impl_get_leadership(self): # pylint: disable=inconsistent-return-statements
|
||||||
|
"""is it a leadership?
|
||||||
|
"""
|
||||||
leadership = self.opt.impl_get_leadership()
|
leadership = self.opt.impl_get_leadership()
|
||||||
if leadership:
|
if leadership:
|
||||||
rootpath = self.rootpath.rsplit('.', 1)[0]
|
rootpath = self.rootpath.rsplit('.', 1)[0]
|
||||||
|
|
|
@ -18,17 +18,21 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""SynDynOptionDescription and SynDynLeadership internal option
|
||||||
|
it's an instanciate synoptiondescription
|
||||||
|
"""
|
||||||
from typing import Optional, Iterator, Any, List
|
from typing import Optional, Iterator, Any, List
|
||||||
|
|
||||||
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from ..setting import ConfigBag, groups, undefined, Settings
|
from ..setting import ConfigBag
|
||||||
from ..value import Values
|
|
||||||
from .baseoption import BaseOption
|
from .baseoption import BaseOption
|
||||||
from .syndynoption import SynDynOption
|
from .syndynoption import SynDynOption
|
||||||
|
|
||||||
|
|
||||||
class SynDynOptionDescription:
|
class SynDynOptionDescription:
|
||||||
|
"""SynDynOptionDescription internal option, it's an instanciate synoptiondescription
|
||||||
|
"""
|
||||||
__slots__ = ('opt',
|
__slots__ = ('opt',
|
||||||
'rootpath',
|
'rootpath',
|
||||||
'_suffix',
|
'_suffix',
|
||||||
|
@ -53,14 +57,14 @@ class SynDynOptionDescription:
|
||||||
name,
|
name,
|
||||||
)
|
)
|
||||||
|
|
||||||
def impl_getopt(self) -> BaseOption:
|
|
||||||
return self.opt
|
|
||||||
|
|
||||||
def get_child(self,
|
def get_child(self,
|
||||||
name: str,
|
name: str,
|
||||||
config_bag: ConfigBag,
|
config_bag: ConfigBag,
|
||||||
subpath: str,
|
subpath: str,
|
||||||
) -> BaseOption:
|
) -> BaseOption:
|
||||||
|
"""get child by name
|
||||||
|
"""
|
||||||
|
# pylint: disable=unused-argument
|
||||||
suffix = self.ori_dyn.convert_suffix_to_path(self._suffix)
|
suffix = self.ori_dyn.convert_suffix_to_path(self._suffix)
|
||||||
if name.endswith(suffix):
|
if name.endswith(suffix):
|
||||||
oname = name[:-len(suffix)]
|
oname = name[:-len(suffix)]
|
||||||
|
@ -78,15 +82,17 @@ class SynDynOptionDescription:
|
||||||
'').format(name, self.impl_get_display_name()))
|
'').format(name, self.impl_get_display_name()))
|
||||||
|
|
||||||
def impl_getname(self) -> str:
|
def impl_getname(self) -> str:
|
||||||
|
"""get name
|
||||||
|
"""
|
||||||
return self.opt.impl_getname() + self.ori_dyn.convert_suffix_to_path(self._suffix)
|
return self.opt.impl_getname() + self.ori_dyn.convert_suffix_to_path(self._suffix)
|
||||||
|
|
||||||
def impl_is_dynoptiondescription(self) -> bool:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def get_children(self,
|
def get_children(self,
|
||||||
config_bag: ConfigBag,
|
config_bag: ConfigBag,
|
||||||
dyn: bool=True,
|
dyn: bool=True,
|
||||||
):
|
):
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
"""get children
|
||||||
|
"""
|
||||||
subpath = self.impl_getpath()
|
subpath = self.impl_getpath()
|
||||||
children = []
|
children = []
|
||||||
for child in self.opt.get_children(config_bag):
|
for child in self.opt.get_children(config_bag):
|
||||||
|
@ -97,6 +103,8 @@ class SynDynOptionDescription:
|
||||||
return children
|
return children
|
||||||
|
|
||||||
def impl_is_dynsymlinkoption(self) -> bool:
|
def impl_is_dynsymlinkoption(self) -> bool:
|
||||||
|
"""it's a dynsymlinkoption
|
||||||
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_children_recursively(self,
|
def get_children_recursively(self,
|
||||||
|
@ -105,6 +113,9 @@ class SynDynOptionDescription:
|
||||||
config_bag: ConfigBag,
|
config_bag: ConfigBag,
|
||||||
self_opt: BaseOption=None,
|
self_opt: BaseOption=None,
|
||||||
) -> BaseOption:
|
) -> BaseOption:
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
"""get children recursively
|
||||||
|
"""
|
||||||
for option in self.opt.get_children_recursively(bytype,
|
for option in self.opt.get_children_recursively(bytype,
|
||||||
byname,
|
byname,
|
||||||
config_bag,
|
config_bag,
|
||||||
|
@ -113,23 +124,33 @@ class SynDynOptionDescription:
|
||||||
yield option
|
yield option
|
||||||
|
|
||||||
def impl_getpath(self) -> str:
|
def impl_getpath(self) -> str:
|
||||||
|
"""get path
|
||||||
|
"""
|
||||||
path = self.impl_getname()
|
path = self.impl_getname()
|
||||||
if self.rootpath:
|
if self.rootpath:
|
||||||
path = f'{self.rootpath}.{path}'
|
path = f'{self.rootpath}.{path}'
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def impl_get_display_name(self) -> str:
|
def impl_get_display_name(self) -> str:
|
||||||
|
"""get display name
|
||||||
|
"""
|
||||||
return self.opt.impl_get_display_name() + str(self._suffix)
|
return self.opt.impl_get_display_name() + str(self._suffix)
|
||||||
|
|
||||||
|
|
||||||
class SynDynLeadership(SynDynOptionDescription):
|
class SynDynLeadership(SynDynOptionDescription):
|
||||||
|
"""SynDynLeadership internal option, it's an instanciate synoptiondescription
|
||||||
|
"""
|
||||||
def get_leader(self) -> SynDynOption:
|
def get_leader(self) -> SynDynOption:
|
||||||
|
"""get the leader
|
||||||
|
"""
|
||||||
return self.opt.get_leader().to_dynoption(self.impl_getpath(),
|
return self.opt.get_leader().to_dynoption(self.impl_getpath(),
|
||||||
self._suffix,
|
self._suffix,
|
||||||
self.ori_dyn,
|
self.ori_dyn,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_followers(self) -> Iterator[SynDynOption]:
|
def get_followers(self) -> Iterator[SynDynOption]:
|
||||||
|
"""get followers
|
||||||
|
"""
|
||||||
subpath = self.impl_getpath()
|
subpath = self.impl_getpath()
|
||||||
for follower in self.opt.get_followers():
|
for follower in self.opt.get_followers():
|
||||||
yield follower.to_dynoption(subpath,
|
yield follower.to_dynoption(subpath,
|
||||||
|
@ -142,6 +163,8 @@ class SynDynLeadership(SynDynOptionDescription):
|
||||||
config_bag: 'ConfigBag',
|
config_bag: 'ConfigBag',
|
||||||
resetted_opts: List[str],
|
resetted_opts: List[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
|
"""reset cache
|
||||||
|
"""
|
||||||
leader = self.get_leader()
|
leader = self.get_leader()
|
||||||
followers = self.get_followers()
|
followers = self.get_followers()
|
||||||
self._reset_cache(path,
|
self._reset_cache(path,
|
||||||
|
@ -155,23 +178,27 @@ class SynDynLeadership(SynDynOptionDescription):
|
||||||
*args,
|
*args,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
"""pop value for a follower
|
||||||
|
"""
|
||||||
self.opt.pop(*args,
|
self.opt.pop(*args,
|
||||||
followers=self.get_followers(),
|
followers=self.get_followers(),
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
def follower_force_store_value(self,
|
def follower_force_store_value(self,
|
||||||
values,
|
|
||||||
value,
|
value,
|
||||||
option_bag,
|
config_bag,
|
||||||
owner,
|
owner,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.opt.follower_force_store_value(values,
|
"""force store value for a follower
|
||||||
value,
|
"""
|
||||||
option_bag,
|
self.opt.follower_force_store_value(value,
|
||||||
|
config_bag,
|
||||||
owner,
|
owner,
|
||||||
dyn=self,
|
dyn=self,
|
||||||
)
|
)
|
||||||
|
|
||||||
def impl_getsuffix(self) -> str:
|
def impl_getsuffix(self) -> str:
|
||||||
|
"""get suffix
|
||||||
|
"""
|
||||||
return self._suffix
|
return self._suffix
|
||||||
|
|
|
@ -18,22 +18,25 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""URLOption to check url value
|
||||||
|
"""
|
||||||
import re
|
import re
|
||||||
from typing import Any, Optional, List, Dict
|
from typing import Any, Optional, List, Dict
|
||||||
|
|
||||||
from ..setting import undefined, Undefined, OptionBag
|
from ..setting import undefined
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
from .option import Option, Calculation
|
from .option import Calculation
|
||||||
from .stroption import StrOption
|
from .stroption import StrOption
|
||||||
from .domainnameoption import DomainnameOption
|
from .domainnameoption import DomainnameOption
|
||||||
from .portoption import PortOption
|
from .portoption import PortOption
|
||||||
|
|
||||||
|
|
||||||
class URLOption(StrOption):
|
class URLOption(StrOption):
|
||||||
|
"""URLOption to check url value
|
||||||
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
path_re = re.compile(r"^[A-Za-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$")
|
path_re = re.compile(r"^[A-Za-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$")
|
||||||
_type = 'url'
|
_type = _('URL')
|
||||||
_display_name = _('URL')
|
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
name: str,
|
name: str,
|
||||||
|
@ -53,8 +56,7 @@ class URLOption(StrOption):
|
||||||
allow_wellknown: bool=True,
|
allow_wellknown: bool=True,
|
||||||
allow_registred: bool=True,
|
allow_registred: bool=True,
|
||||||
allow_private: bool=False) -> None:
|
allow_private: bool=False) -> None:
|
||||||
|
# pylint: disable=too-many-arguments,too-many-locals,redefined-builtin
|
||||||
|
|
||||||
extra = {'_domainname': DomainnameOption(name,
|
extra = {'_domainname': DomainnameOption(name,
|
||||||
doc,
|
doc,
|
||||||
allow_ip=allow_ip,
|
allow_ip=allow_ip,
|
||||||
|
@ -80,10 +82,10 @@ class URLOption(StrOption):
|
||||||
def _get_domain_port_files(self,
|
def _get_domain_port_files(self,
|
||||||
value: str) -> (str, str):
|
value: str) -> (str, str):
|
||||||
if value.startswith('http://'):
|
if value.startswith('http://'):
|
||||||
type = 'http'
|
type_ = 'http'
|
||||||
value = value[7:]
|
value = value[7:]
|
||||||
elif value.startswith('https://'):
|
elif value.startswith('https://'):
|
||||||
type = 'https'
|
type_ = 'https'
|
||||||
value = value[8:]
|
value = value[8:]
|
||||||
else:
|
else:
|
||||||
raise ValueError(_('must start with http:// or '
|
raise ValueError(_('must start with http:// or '
|
||||||
|
@ -100,7 +102,7 @@ class URLOption(StrOption):
|
||||||
if len(splitted) == 1:
|
if len(splitted) == 1:
|
||||||
domain = splitted[0]
|
domain = splitted[0]
|
||||||
port = {'http': '80',
|
port = {'http': '80',
|
||||||
'https': '443'}[type]
|
'https': '443'}[type_]
|
||||||
else:
|
else:
|
||||||
domain, port = splitted
|
domain, port = splitted
|
||||||
return domain, port, files
|
return domain, port, files
|
||||||
|
@ -120,7 +122,7 @@ class URLOption(StrOption):
|
||||||
raise ValueError(_('must ends with a valid resource name'))
|
raise ValueError(_('must ends with a valid resource name'))
|
||||||
|
|
||||||
def second_level_validation(self, value, warnings_only):
|
def second_level_validation(self, value, warnings_only):
|
||||||
domain, port, files = self._get_domain_port_files(value)
|
domain, port, _ = self._get_domain_port_files(value)
|
||||||
# validate port
|
# validate port
|
||||||
portoption = self.impl_get_extra('_port')
|
portoption = self.impl_get_extra('_port')
|
||||||
portoption.second_level_validation(port, warnings_only)
|
portoption.second_level_validation(port, warnings_only)
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
# the whole pypy projet is under MIT licence
|
# the whole pypy projet is under MIT licence
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
"""UsernameOption or GroupnameOption to check unix username/group value
|
||||||
|
"""
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from ..i18n import _
|
from ..i18n import _
|
||||||
|
@ -25,14 +27,16 @@ from .stroption import RegexpOption
|
||||||
|
|
||||||
|
|
||||||
class UsernameOption(RegexpOption):
|
class UsernameOption(RegexpOption):
|
||||||
|
"""UsernameOption to check unix username value
|
||||||
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
#regexp build with 'man 8 adduser' informations
|
#regexp build with 'man 8 adduser' informations
|
||||||
_regexp = re.compile(r"^[a-z_][a-z0-9_-]{0,30}[$a-z0-9_-]{0,1}$")
|
_regexp = re.compile(r"^[a-z_][a-z0-9_-]{0,30}[$a-z0-9_-]{0,1}$")
|
||||||
_type = 'username'
|
_type = _('unix username')
|
||||||
_display_name = _('unix username')
|
|
||||||
|
|
||||||
|
|
||||||
class GroupnameOption(UsernameOption):
|
class GroupnameOption(UsernameOption):
|
||||||
|
"""GroupnameOption to check unix group value
|
||||||
|
"""
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
_type = 'groupname'
|
_type = _('unix groupname')
|
||||||
_display_name = _('unix groupname')
|
|
||||||
|
|
|
@ -15,94 +15,92 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
from typing import Union
|
from typing import Union, Set
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from .error import PropertiesOptionError, ConstError, ConfigError, LeadershipError, display_list
|
from .error import PropertiesOptionError, ConstError, ConfigError, LeadershipError
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
|
|
||||||
|
|
||||||
"""If cache and expire is enable, time before cache is expired.
|
# If cache and expire is enable, time before cache is expired.
|
||||||
This delay start first time value/setting is set in cache, even if
|
# This delay start first time value/setting is set in cache, even if
|
||||||
user access several time to value/setting
|
# user access several time to value/setting
|
||||||
"""
|
|
||||||
EXPIRATION_TIME = 5
|
EXPIRATION_TIME = 5
|
||||||
"""List of default properties (you can add new one if needed).
|
|
||||||
|
|
||||||
For common properties and personalise properties, if a propery is set for
|
#List of default properties (you can add new one if needed).
|
||||||
an Option and for the Config together, Setting raise a PropertiesOptionError
|
#
|
||||||
|
#For common properties and personalise properties, if a propery is set for
|
||||||
* Common properties:
|
#an Option and for the Config together, Setting raise a PropertiesOptionError
|
||||||
|
#
|
||||||
hidden
|
#* Common properties:
|
||||||
option with this property can only get value in read only mode. This
|
#
|
||||||
option is not available in read write mode.
|
#hidden
|
||||||
|
# option with this property can only get value in read only mode. This
|
||||||
disabled
|
# option is not available in read write mode.
|
||||||
option with this property cannot be set/get
|
#
|
||||||
|
#disabled
|
||||||
frozen
|
# option with this property cannot be set/get
|
||||||
cannot set value for option with this properties if 'frozen' is set in
|
#
|
||||||
config
|
#frozen
|
||||||
|
# cannot set value for option with this properties if 'frozen' is set in
|
||||||
* Special property:
|
# config
|
||||||
|
#
|
||||||
permissive
|
#* Special property:
|
||||||
option with 'permissive' cannot raise PropertiesOptionError for properties
|
#
|
||||||
set in permissive
|
#permissive
|
||||||
config with 'permissive', whole option in this config cannot raise
|
# option with 'permissive' cannot raise PropertiesOptionError for properties
|
||||||
PropertiesOptionError for properties set in permissive
|
# set in permissive
|
||||||
|
# config with 'permissive', whole option in this config cannot raise
|
||||||
mandatory
|
# PropertiesOptionError for properties set in permissive
|
||||||
should set value for option with this properties if 'mandatory' is set in
|
#
|
||||||
config
|
#mandatory
|
||||||
example: 'a', ['a'], [None] are valid
|
# should set value for option with this properties if 'mandatory' is set in
|
||||||
None, [] are not valid
|
# config
|
||||||
|
# example: 'a', ['a'], [None] are valid
|
||||||
empty
|
# None, [] are not valid
|
||||||
raise mandatory PropertiesOptionError if multi or leader have empty value
|
#
|
||||||
example: ['a'] is valid
|
#empty
|
||||||
[None] is not valid
|
# raise mandatory PropertiesOptionError if multi or leader have empty value
|
||||||
|
# example: ['a'] is valid
|
||||||
unique
|
# [None] is not valid
|
||||||
raise ValueError if a value is set twice or more in a multi Option
|
#
|
||||||
|
#unique
|
||||||
* Special Config properties:
|
# raise ValueError if a value is set twice or more in a multi Option
|
||||||
|
#
|
||||||
cache
|
#* Special Config properties:
|
||||||
if set, enable cache settings and values
|
#
|
||||||
|
#cache
|
||||||
expire
|
# if set, enable cache settings and values
|
||||||
if set, settings and values in cache expire after ``expiration_time``
|
#
|
||||||
|
#expire
|
||||||
everything_frozen
|
# if set, settings and values in cache expire after ``expiration_time``
|
||||||
whole option in config are frozen (even if option have not frozen
|
#
|
||||||
property)
|
#everything_frozen
|
||||||
|
# whole option in config are frozen (even if option have not frozen
|
||||||
validator
|
# property)
|
||||||
launch validator set by user in option (this property has no effect
|
#
|
||||||
for internal validator)
|
#validator
|
||||||
|
# launch validator set by user in option (this property has no effect
|
||||||
warnings
|
# for internal validator)
|
||||||
display warnings during validation
|
#
|
||||||
|
#warnings
|
||||||
demoting_error_warning
|
# display warnings during validation
|
||||||
all value errors are convert to warning (ValueErrorWarning)
|
#
|
||||||
"""
|
#demoting_error_warning
|
||||||
|
# all value errors are convert to warning (ValueErrorWarning)
|
||||||
DEFAULT_PROPERTIES = frozenset(['cache', 'validator', 'warnings'])
|
DEFAULT_PROPERTIES = frozenset(['cache', 'validator', 'warnings'])
|
||||||
SPECIAL_PROPERTIES = {'frozen', 'mandatory', 'empty', 'force_store_value'}
|
SPECIAL_PROPERTIES = {'frozen', 'mandatory', 'empty', 'force_store_value'}
|
||||||
|
|
||||||
"""Config can be in two defaut mode:
|
#Config can be in two defaut mode:
|
||||||
|
#
|
||||||
read_only
|
#read_only
|
||||||
you can get all variables not disabled but you cannot set any variables
|
# you can get all variables not disabled but you cannot set any variables
|
||||||
if a value has a callback without any value, callback is launch and value
|
# if a value has a callback without any value, callback is launch and value
|
||||||
of this variable can change
|
# of this variable can change
|
||||||
you cannot access to mandatory variable without values
|
# you cannot access to mandatory variable without values
|
||||||
|
#
|
||||||
read_write
|
#read_write
|
||||||
you can get all variables not disabled and not hidden
|
# you can get all variables not disabled and not hidden
|
||||||
you can set all variables not frozen
|
# you can set all variables not frozen
|
||||||
"""
|
|
||||||
RO_APPEND = frozenset(['frozen',
|
RO_APPEND = frozenset(['frozen',
|
||||||
'disabled',
|
'disabled',
|
||||||
'validator',
|
'validator',
|
||||||
|
@ -147,7 +145,10 @@ static_set = frozenset()
|
||||||
|
|
||||||
|
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
class Undefined(object):
|
class Undefined:
|
||||||
|
"""Object undefined, means that there is not value
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
def __str__(self): # pragma: no cover
|
def __str__(self): # pragma: no cover
|
||||||
return 'Undefined'
|
return 'Undefined'
|
||||||
|
|
||||||
|
@ -158,6 +159,8 @@ undefined = Undefined()
|
||||||
|
|
||||||
|
|
||||||
class OptionBag:
|
class OptionBag:
|
||||||
|
"""Object to store information for an option
|
||||||
|
"""
|
||||||
__slots__ = ('option', # current option
|
__slots__ = ('option', # current option
|
||||||
'path',
|
'path',
|
||||||
'index',
|
'index',
|
||||||
|
@ -167,6 +170,7 @@ class OptionBag:
|
||||||
'apply_requires', # apply requires or not for this option
|
'apply_requires', # apply requires or not for this option
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# pylint: disable=too-many-arguments
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
option,
|
option,
|
||||||
index,
|
index,
|
||||||
|
@ -187,42 +191,39 @@ class OptionBag:
|
||||||
self.path = path
|
self.path = path
|
||||||
elif option:
|
elif option:
|
||||||
self.path = option.impl_getpath()
|
self.path = option.impl_getpath()
|
||||||
if '.' not in self.path and option == config_bag.context.get_description():
|
context = config_bag.context
|
||||||
|
if '.' not in self.path and option == context.get_description():
|
||||||
self.properties = None
|
self.properties = None
|
||||||
elif properties is undefined:
|
elif properties is undefined:
|
||||||
self.properties = config_bag.context.get_settings().getproperties(self, apply_requires=apply_requires)
|
settings = context.get_settings()
|
||||||
|
self.properties = settings.getproperties(self,
|
||||||
|
apply_requires=apply_requires,
|
||||||
|
)
|
||||||
if properties is not undefined:
|
if properties is not undefined:
|
||||||
self.properties = properties
|
self.properties = properties
|
||||||
|
|
||||||
def __getattr__(self, key):
|
def __getattr__(self, key):
|
||||||
if key == 'ori_option':
|
if key == 'ori_option':
|
||||||
return self.option
|
return self.option
|
||||||
elif key == 'apply_requires':
|
if key == 'apply_requires':
|
||||||
return True
|
return True
|
||||||
return undefined
|
return None
|
||||||
|
|
||||||
def __delattr__(self, key):
|
|
||||||
if key in ['properties', 'permissives']:
|
|
||||||
try:
|
|
||||||
super().__delattr__(key)
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
return
|
|
||||||
raise KeyError(_('cannot delete key "{}" for OptionBag').format(key)) # pragma: no cover
|
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
|
"""copy OptionBag
|
||||||
|
"""
|
||||||
option_bag = OptionBag(None,
|
option_bag = OptionBag(None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
for key in self.__slots__:
|
for key in self.__slots__:
|
||||||
if not hasattr(self, key):
|
|
||||||
continue
|
|
||||||
setattr(option_bag, key, getattr(self, key))
|
setattr(option_bag, key, getattr(self, key))
|
||||||
return option_bag
|
return option_bag
|
||||||
|
|
||||||
|
|
||||||
class ConfigBag:
|
class ConfigBag:
|
||||||
|
"""Object to store information for context
|
||||||
|
"""
|
||||||
__slots__ = ('context', # link to the current context
|
__slots__ = ('context', # link to the current context
|
||||||
'properties', # properties for current context
|
'properties', # properties for current context
|
||||||
'true_properties', # properties for current context
|
'true_properties', # properties for current context
|
||||||
|
@ -246,30 +247,37 @@ class ConfigBag:
|
||||||
if key == 'true_properties':
|
if key == 'true_properties':
|
||||||
return self.properties
|
return self.properties
|
||||||
if key == 'expiration_time':
|
if key == 'expiration_time':
|
||||||
self.expiration_time = EXPIRATION_TIME
|
self.expiration_time = EXPIRATION_TIME # pylint: disable=attribute-defined-outside-init
|
||||||
return self.expiration_time
|
return self.expiration_time
|
||||||
if key == 'is_unrestraint':
|
if key == 'is_unrestraint':
|
||||||
return False
|
return False
|
||||||
raise KeyError('unknown key "{}" for ConfigBag'.format(key)) # pragma: no cover
|
raise KeyError(f'unknown key "{key}" for ConfigBag') # pragma: no cover
|
||||||
|
|
||||||
def __setattr__(self, key, value):
|
def nowarnings(self):
|
||||||
super().__setattr__(key, value)
|
"""do not warnings
|
||||||
|
"""
|
||||||
def remove_warnings(self):
|
|
||||||
self.properties = frozenset(self.properties - {'warnings'})
|
self.properties = frozenset(self.properties - {'warnings'})
|
||||||
|
|
||||||
def remove_validation(self):
|
def remove_validation(self):
|
||||||
|
"""do not validate option
|
||||||
|
"""
|
||||||
self.properties = frozenset(self.properties - {'validator'})
|
self.properties = frozenset(self.properties - {'validator'})
|
||||||
|
|
||||||
def unrestraint(self):
|
def unrestraint(self):
|
||||||
self.is_unrestraint = True
|
"""do not restraint access to option
|
||||||
self.true_properties = self.properties
|
"""
|
||||||
|
self.is_unrestraint = True # pylint: disable=attribute-defined-outside-init
|
||||||
|
self.true_properties = self.properties # pylint: disable=attribute-defined-outside-init
|
||||||
self.properties = frozenset(['cache'])
|
self.properties = frozenset(['cache'])
|
||||||
|
|
||||||
def set_permissive(self):
|
def set_permissive(self):
|
||||||
|
"""set permissive
|
||||||
|
"""
|
||||||
self.properties = frozenset(self.properties | {'permissive'})
|
self.properties = frozenset(self.properties | {'permissive'})
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
|
"""copy the config
|
||||||
|
"""
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
for key in self.__slots__:
|
for key in self.__slots__:
|
||||||
kwargs[key] = getattr(self, key)
|
kwargs[key] = getattr(self, key)
|
||||||
|
@ -277,7 +285,7 @@ class ConfigBag:
|
||||||
|
|
||||||
|
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
class _NameSpace(object):
|
class _NameSpace:
|
||||||
"""convenient class that emulates a module
|
"""convenient class that emulates a module
|
||||||
and builds constants (that is, unique names)
|
and builds constants (that is, unique names)
|
||||||
when attribute is added, we cannot delete it
|
when attribute is added, we cannot delete it
|
||||||
|
@ -299,28 +307,27 @@ class _NameSpace(object):
|
||||||
|
|
||||||
class GroupModule(_NameSpace):
|
class GroupModule(_NameSpace):
|
||||||
"emulates a module to manage unique group (OptionDescription) names"
|
"emulates a module to manage unique group (OptionDescription) names"
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
class GroupType(str):
|
class GroupType(str):
|
||||||
"""allowed normal group (OptionDescription) names
|
"""allowed normal group (OptionDescription) names
|
||||||
*normal* means : groups that are not leader
|
*normal* means : groups that are not leader
|
||||||
"""
|
"""
|
||||||
pass
|
|
||||||
|
|
||||||
class DefaultGroupType(GroupType):
|
class DefaultGroupType(GroupType):
|
||||||
"""groups that are default (typically 'default')"""
|
"""groups that are default (typically 'default')"""
|
||||||
pass
|
|
||||||
|
|
||||||
class LeadershipGroupType(GroupType):
|
class LeadershipGroupType(GroupType):
|
||||||
"""allowed normal group (OptionDescription) names
|
"""allowed normal group (OptionDescription) names
|
||||||
*leadership* means : groups that have the 'leadership' attribute set
|
*leadership* means : groups that have the 'leadership' attribute set
|
||||||
"""
|
"""
|
||||||
pass
|
|
||||||
|
|
||||||
class RootGroupType(GroupType):
|
class RootGroupType(GroupType):
|
||||||
"""root means this is the root optiondescription of whole config
|
"""root means this is the root optiondescription of whole config
|
||||||
"""
|
"""
|
||||||
pass
|
|
||||||
|
|
||||||
def addgroup(self, name):
|
def addgroup(self, name):
|
||||||
|
"""add a new group type
|
||||||
|
"""
|
||||||
setattr(groups, name, groups.GroupType(name))
|
setattr(groups, name, groups.GroupType(name))
|
||||||
|
|
||||||
|
|
||||||
|
@ -329,14 +336,13 @@ class OwnerModule(_NameSpace):
|
||||||
|
|
||||||
owners are living in `Config._value_owners`
|
owners are living in `Config._value_owners`
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
class Owner(str):
|
class Owner(str):
|
||||||
"""allowed owner names
|
"""allowed owner names
|
||||||
"""
|
"""
|
||||||
pass
|
|
||||||
|
|
||||||
class DefaultOwner(Owner):
|
class DefaultOwner(Owner):
|
||||||
"""groups that are default (typically 'default')"""
|
"""groups that are default (typically 'default')"""
|
||||||
pass
|
|
||||||
|
|
||||||
def addowner(self, name):
|
def addowner(self, name):
|
||||||
"""
|
"""
|
||||||
|
@ -348,41 +354,39 @@ class OwnerModule(_NameSpace):
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
# populate groups
|
# populate groups
|
||||||
groups = GroupModule()
|
groups = GroupModule()
|
||||||
"""groups.default
|
|
||||||
default group set when creating a new optiondescription"""
|
|
||||||
groups.default = groups.DefaultGroupType('default')
|
|
||||||
|
|
||||||
"""groups.leadership
|
# groups.default: default group set when creating a new optiondescription
|
||||||
leadership group is a special optiondescription, all suboptions should
|
groups.default = groups.DefaultGroupType('default') # pylint: disable=attribute-defined-outside-init
|
||||||
be multi option and all values should have same length, to find
|
|
||||||
leader's option, the optiondescription's name should be same than de
|
|
||||||
leader's option"""
|
|
||||||
groups.leadership = groups.LeadershipGroupType('leadership')
|
|
||||||
|
|
||||||
""" groups.root
|
# groups.leadership: leadership group is a special optiondescription, all suboptions should
|
||||||
this group is the root optiondescription of whole config"""
|
# be multi option and all values should have same length, to find
|
||||||
groups.root = groups.RootGroupType('root')
|
# leader's option, the optiondescription's name should be same than de
|
||||||
|
# leader's option"""
|
||||||
|
groups.leadership = groups.LeadershipGroupType('leadership') # pylint: disable=attribute-defined-outside-init
|
||||||
|
|
||||||
|
# groups.root: this group is the root optiondescription of whole config
|
||||||
|
groups.root = groups.RootGroupType('root') # pylint: disable=attribute-defined-outside-init
|
||||||
|
|
||||||
|
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
# populate owners with default attributes
|
# populate owners with default attributes
|
||||||
owners = OwnerModule()
|
owners = OwnerModule()
|
||||||
"""default
|
|
||||||
is the config owner after init time"""
|
# default: is the config owner after init time
|
||||||
owners.default = owners.DefaultOwner('default')
|
owners.default = owners.DefaultOwner('default') # pylint: disable=attribute-defined-outside-init
|
||||||
"""user
|
|
||||||
is the generic is the generic owner"""
|
# user: is the generic is the generic owner
|
||||||
owners.user = owners.Owner('user')
|
owners.addowner('user')
|
||||||
"""forced
|
|
||||||
special owner when value is forced"""
|
#forced: special owner when value is forced
|
||||||
owners.forced = owners.Owner('forced')
|
owners.addowner('forced')
|
||||||
|
|
||||||
|
|
||||||
forbidden_owners = (owners.default, owners.forced)
|
forbidden_owners = (owners.default, owners.forced) # pylint: disable=no-member
|
||||||
|
|
||||||
|
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
class Settings(object):
|
class Settings:
|
||||||
"``config.Config()``'s configuration options settings"
|
"``config.Config()``'s configuration options settings"
|
||||||
__slots__ = ('_properties',
|
__slots__ = ('_properties',
|
||||||
'_permissives',
|
'_permissives',
|
||||||
|
@ -417,33 +421,33 @@ class Settings(object):
|
||||||
def get_context_properties(self,
|
def get_context_properties(self,
|
||||||
cache,
|
cache,
|
||||||
):
|
):
|
||||||
is_cached, props, validated = cache.getcache(None,
|
"""get context properties
|
||||||
None,
|
"""
|
||||||
None,
|
is_cached, props, _ = cache.getcache(None,
|
||||||
{},
|
'context_props',
|
||||||
{},
|
expiration=False,
|
||||||
'context_props',
|
)
|
||||||
)
|
|
||||||
if not is_cached:
|
if not is_cached:
|
||||||
props = self._properties.get(None, {}).get(None, self.default_properties)
|
props = self.get_stored_properties(None,
|
||||||
|
None,
|
||||||
|
self.default_properties,
|
||||||
|
)
|
||||||
cache.setcache(None,
|
cache.setcache(None,
|
||||||
None,
|
|
||||||
props,
|
props,
|
||||||
{},
|
type_='properties',
|
||||||
props,
|
)
|
||||||
True)
|
|
||||||
return props
|
return props
|
||||||
|
|
||||||
def _getproperties(self,
|
def get_stored_properties(self,
|
||||||
path,
|
path: Union[None, str],
|
||||||
index,
|
index: Union[None, int],
|
||||||
default_properties,
|
default_properties: Set[str],
|
||||||
):
|
) -> Set[str]:
|
||||||
if path not in self._properties:
|
"""Get the properties modified by user for a path or index
|
||||||
ret = frozenset(default_properties)
|
"""
|
||||||
else:
|
if path not in self._properties or index not in self._properties[path]:
|
||||||
ret = self._properties[path].get(index, frozenset(default_properties))
|
return frozenset(default_properties)
|
||||||
return ret
|
return self._properties[path][index]
|
||||||
|
|
||||||
def getproperties(self,
|
def getproperties(self,
|
||||||
option_bag,
|
option_bag,
|
||||||
|
@ -451,21 +455,15 @@ class Settings(object):
|
||||||
uncalculated=False,
|
uncalculated=False,
|
||||||
help_property=False,
|
help_property=False,
|
||||||
):
|
):
|
||||||
|
"""get properties
|
||||||
"""
|
"""
|
||||||
"""
|
# pylint: disable=too-many-branches
|
||||||
option = option_bag.option
|
option = option_bag.option
|
||||||
config_bag = option_bag.config_bag
|
|
||||||
if option.impl_is_symlinkoption():
|
if option.impl_is_symlinkoption():
|
||||||
option = option.impl_getopt()
|
option = option.impl_getopt()
|
||||||
path = option.impl_getpath()
|
|
||||||
index = option_bag.index
|
|
||||||
if apply_requires and not uncalculated and not help_property:
|
if apply_requires and not uncalculated and not help_property:
|
||||||
cache = config_bag.context.properties_cache
|
cache = option_bag.config_bag.context.properties_cache
|
||||||
is_cached, props, validated = cache.getcache(path,
|
is_cached, props, validated = cache.getcache(option_bag, # pylint: disable=unused-variable
|
||||||
config_bag.expiration_time,
|
|
||||||
index,
|
|
||||||
config_bag.properties,
|
|
||||||
{},
|
|
||||||
'self_props',
|
'self_props',
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
@ -473,13 +471,16 @@ class Settings(object):
|
||||||
if not is_cached:
|
if not is_cached:
|
||||||
props = set()
|
props = set()
|
||||||
# if index, get option's properties (without index) too
|
# if index, get option's properties (without index) too
|
||||||
p_props = self._getproperties(path,
|
p_props = self.get_stored_properties(option_bag.path,
|
||||||
None,
|
None,
|
||||||
option.impl_getproperties(),
|
option.impl_getproperties(),
|
||||||
)
|
)
|
||||||
if index is not None:
|
if option_bag.index is not None:
|
||||||
p_props = chain(p_props,
|
p_props = chain(p_props,
|
||||||
self._properties.get(path, {}).get(index, option.impl_getproperties())
|
self.get_stored_properties(option_bag.path,
|
||||||
|
option_bag.index,
|
||||||
|
option.impl_getproperties(),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
for prop in p_props:
|
for prop in p_props:
|
||||||
if uncalculated or isinstance(prop, str):
|
if uncalculated or isinstance(prop, str):
|
||||||
|
@ -502,43 +503,29 @@ class Settings(object):
|
||||||
new_prop = (new_prop, new_prop)
|
new_prop = (new_prop, new_prop)
|
||||||
if new_prop is None:
|
if new_prop is None:
|
||||||
continue
|
continue
|
||||||
elif (not help_property and not isinstance(new_prop, str)) or \
|
if (not help_property and not isinstance(new_prop, str)) or \
|
||||||
(help_property and not isinstance(new_prop, tuple)):
|
(help_property and not isinstance(new_prop, tuple)):
|
||||||
raise ValueError(_('invalid property type {} for {} with {} function').format(type(new_prop),
|
raise ValueError(_('invalid property type {type(new_prop)} for '
|
||||||
option_bag.option.impl_getname(),
|
'{option_bag.option.impl_getname()} with '
|
||||||
prop.function.__name__))
|
'{prop.function.__name__} function'))
|
||||||
if not option.impl_is_optiondescription() and \
|
if not option.impl_is_optiondescription() and \
|
||||||
option.impl_is_leader() and \
|
option.impl_is_leader() and \
|
||||||
new_prop not in ALLOWED_LEADER_PROPERTIES:
|
new_prop not in ALLOWED_LEADER_PROPERTIES:
|
||||||
raise LeadershipError(_('leader cannot have "{}" property').format(new_prop))
|
raise LeadershipError(_('leader cannot have "{new_prop}" property'))
|
||||||
props.add(new_prop)
|
props.add(new_prop)
|
||||||
props -= self.getpermissives(option_bag)
|
props -= self.getpermissives(option_bag)
|
||||||
if not uncalculated and apply_requires and not config_bag.is_unrestraint and not help_property:
|
if not uncalculated and apply_requires and \
|
||||||
cache.setcache(path,
|
not option_bag.config_bag.is_unrestraint and \
|
||||||
index,
|
not help_property:
|
||||||
|
cache.setcache(option_bag,
|
||||||
props,
|
props,
|
||||||
props,
|
type_='properties',
|
||||||
config_bag.properties,
|
)
|
||||||
True)
|
|
||||||
return props
|
return props
|
||||||
|
|
||||||
def has_properties_index(self,
|
|
||||||
option_bag):
|
|
||||||
option = option_bag.option
|
|
||||||
if option.impl_is_symlinkoption():
|
|
||||||
option = option.impl_getopt()
|
|
||||||
path = option.impl_getpath()
|
|
||||||
p_props = self._properties.get(path, {}).get(None, option.impl_getproperties())
|
|
||||||
if option_bag.index is not None:
|
|
||||||
p_props = chain(p_props,
|
|
||||||
self._properties.get(path, {}).get(option_bag.index, option.impl_getproperties()),
|
|
||||||
)
|
|
||||||
for prop in p_props:
|
|
||||||
if not isinstance(prop, str) and prop.has_index(option_bag.option):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_context_permissives(self):
|
def get_context_permissives(self):
|
||||||
|
"""get context permissives
|
||||||
|
"""
|
||||||
return self.getpermissives(None)
|
return self.getpermissives(None)
|
||||||
|
|
||||||
def _getpermissives(self,
|
def _getpermissives(self,
|
||||||
|
@ -554,6 +541,8 @@ class Settings(object):
|
||||||
def getpermissives(self,
|
def getpermissives(self,
|
||||||
option_bag,
|
option_bag,
|
||||||
):
|
):
|
||||||
|
"""get permissive
|
||||||
|
"""
|
||||||
if option_bag is None:
|
if option_bag is None:
|
||||||
path = None
|
path = None
|
||||||
index = None
|
index = None
|
||||||
|
@ -576,6 +565,8 @@ class Settings(object):
|
||||||
#____________________________________________________________
|
#____________________________________________________________
|
||||||
# set methods
|
# set methods
|
||||||
def set_context_properties(self, properties, context):
|
def set_context_properties(self, properties, context):
|
||||||
|
"""set context properties
|
||||||
|
"""
|
||||||
self._properties.setdefault(None, {})[None] = properties
|
self._properties.setdefault(None, {})[None] = properties
|
||||||
context.reset_cache(None)
|
context.reset_cache(None)
|
||||||
|
|
||||||
|
@ -587,21 +578,16 @@ class Settings(object):
|
||||||
(never save properties if same has option properties)
|
(never save properties if same has option properties)
|
||||||
"""
|
"""
|
||||||
opt = option_bag.option
|
opt = option_bag.option
|
||||||
if opt.impl_is_symlinkoption():
|
|
||||||
raise TypeError(_("can't assign property to the symlinkoption \"{}\""
|
|
||||||
"").format(opt.impl_get_display_name()))
|
|
||||||
if not opt.impl_is_optiondescription() and opt.impl_is_leader():
|
if not opt.impl_is_optiondescription() and opt.impl_is_leader():
|
||||||
not_allowed_properties = properties - ALLOWED_LEADER_PROPERTIES
|
not_allowed_properties = properties - ALLOWED_LEADER_PROPERTIES
|
||||||
if not_allowed_properties:
|
if not_allowed_properties:
|
||||||
if len(not_allowed_properties) == 1:
|
raise LeadershipError(_('leader cannot have "{list(not_allowed_properties)}" '
|
||||||
raise LeadershipError(_('leader cannot have "{}" property').format(list(not_allowed_properties)[0]))
|
'property'))
|
||||||
else:
|
if ('force_default_on_freeze' in properties or \
|
||||||
raise LeadershipError(_('leader cannot have {} properties').format(display_list(list(not_allowed_properties), add_quote=True)))
|
'force_metaconfig_on_freeze' in properties) and 'frozen' not in properties:
|
||||||
if ('force_default_on_freeze' in properties or 'force_metaconfig_on_freeze' in properties) and \
|
raise LeadershipError(_('a leader ({opt.impl_get_display_name()}) cannot have '
|
||||||
'frozen' not in properties:
|
'"force_default_on_freeze" or '
|
||||||
raise LeadershipError(_('a leader ({0}) cannot have '
|
'"force_metaconfig_on_freeze" property without "frozen"'))
|
||||||
'"force_default_on_freeze" or "force_metaconfig_on_freeze" property without "frozen"'
|
|
||||||
'').format(opt.impl_get_display_name()))
|
|
||||||
self._properties.setdefault(option_bag.path, {})[option_bag.index] = properties
|
self._properties.setdefault(option_bag.path, {})[option_bag.index] = properties
|
||||||
# values too because of follower values could have a PropertiesOptionError has value
|
# values too because of follower values could have a PropertiesOptionError has value
|
||||||
option_bag.config_bag.context.reset_cache(option_bag)
|
option_bag.config_bag.context.reset_cache(option_bag)
|
||||||
|
@ -610,6 +596,8 @@ class Settings(object):
|
||||||
def set_context_permissives(self,
|
def set_context_permissives(self,
|
||||||
permissives,
|
permissives,
|
||||||
):
|
):
|
||||||
|
"""set context permissive
|
||||||
|
"""
|
||||||
self.setpermissives(None,
|
self.setpermissives(None,
|
||||||
permissives,
|
permissives,
|
||||||
)
|
)
|
||||||
|
@ -630,10 +618,6 @@ class Settings(object):
|
||||||
if not isinstance(permissives, frozenset):
|
if not isinstance(permissives, frozenset):
|
||||||
raise TypeError(_('permissive must be a frozenset'))
|
raise TypeError(_('permissive must be a frozenset'))
|
||||||
if option_bag is not None:
|
if option_bag is not None:
|
||||||
opt = option_bag.option
|
|
||||||
if opt and opt.impl_is_symlinkoption():
|
|
||||||
raise TypeError(_("can't assign permissive to the symlinkoption \"{}\""
|
|
||||||
"").format(opt.impl_get_display_name()))
|
|
||||||
path = option_bag.path
|
path = option_bag.path
|
||||||
index = option_bag.index
|
index = option_bag.index
|
||||||
else:
|
else:
|
||||||
|
@ -670,25 +654,29 @@ class Settings(object):
|
||||||
def reset(self,
|
def reset(self,
|
||||||
bag: Union[OptionBag, ConfigBag],
|
bag: Union[OptionBag, ConfigBag],
|
||||||
):
|
):
|
||||||
|
"""reset property
|
||||||
|
"""
|
||||||
path, index, config_bag, option_bag = \
|
path, index, config_bag, option_bag = \
|
||||||
self._get_path_index_config_option(bag,
|
self._get_path_index_config_option(bag,
|
||||||
"can't reset properties to "
|
"can't reset properties to "
|
||||||
"the symlinkoption \"{}\"",
|
"the symlinkoption \"{}\"",
|
||||||
)
|
)
|
||||||
if path in self._properties and index in self._properties[path]:
|
if path in self._properties and index in self._properties[path]:
|
||||||
del(self._properties[path][index])
|
del self._properties[path][index]
|
||||||
config_bag.context.reset_cache(option_bag)
|
config_bag.context.reset_cache(option_bag)
|
||||||
|
|
||||||
def reset_permissives(self,
|
def reset_permissives(self,
|
||||||
bag: Union[OptionBag, ConfigBag],
|
bag: Union[OptionBag, ConfigBag],
|
||||||
):
|
):
|
||||||
|
"""reset permission
|
||||||
|
"""
|
||||||
path, index, config_bag, option_bag = \
|
path, index, config_bag, option_bag = \
|
||||||
self._get_path_index_config_option(bag,
|
self._get_path_index_config_option(bag,
|
||||||
"can't reset permissives to "
|
"can't reset permissives to "
|
||||||
"the symlinkoption \"{}\"",
|
"the symlinkoption \"{}\"",
|
||||||
)
|
)
|
||||||
if path in self._permissives and index in self._permissives[path]:
|
if path in self._permissives and index in self._permissives[path]:
|
||||||
del(self._permissives[path][index])
|
del self._permissives[path][index]
|
||||||
config_bag.context.reset_cache(option_bag)
|
config_bag.context.reset_cache(option_bag)
|
||||||
|
|
||||||
#____________________________________________________________
|
#____________________________________________________________
|
||||||
|
@ -698,6 +686,8 @@ class Settings(object):
|
||||||
apply_requires=True,
|
apply_requires=True,
|
||||||
uncalculated=False,
|
uncalculated=False,
|
||||||
):
|
):
|
||||||
|
"""raise if needed
|
||||||
|
"""
|
||||||
if not uncalculated and apply_requires:
|
if not uncalculated and apply_requires:
|
||||||
option_properties = option_bag.properties
|
option_properties = option_bag.properties
|
||||||
else:
|
else:
|
||||||
|
@ -707,12 +697,14 @@ class Settings(object):
|
||||||
)
|
)
|
||||||
return self._calc_raises_properties(option_bag.config_bag.properties,
|
return self._calc_raises_properties(option_bag.config_bag.properties,
|
||||||
option_bag.config_bag.permissives,
|
option_bag.config_bag.permissives,
|
||||||
option_properties)
|
option_properties,
|
||||||
|
)
|
||||||
|
|
||||||
def _calc_raises_properties(self,
|
def _calc_raises_properties(self,
|
||||||
context_properties,
|
context_properties,
|
||||||
context_permissives,
|
context_permissives,
|
||||||
option_properties):
|
option_properties,
|
||||||
|
):
|
||||||
raises_properties = context_properties - SPECIAL_PROPERTIES
|
raises_properties = context_properties - SPECIAL_PROPERTIES
|
||||||
# remove global permissive properties
|
# remove global permissive properties
|
||||||
if raises_properties and 'permissive' in raises_properties:
|
if raises_properties and 'permissive' in raises_properties:
|
||||||
|
@ -725,6 +717,8 @@ class Settings(object):
|
||||||
option_bag,
|
option_bag,
|
||||||
need_help=True,
|
need_help=True,
|
||||||
):
|
):
|
||||||
|
"""check properties
|
||||||
|
"""
|
||||||
config_properties = option_bag.config_bag.properties
|
config_properties = option_bag.config_bag.properties
|
||||||
if not config_properties or config_properties == frozenset(['cache']):
|
if not config_properties or config_properties == frozenset(['cache']):
|
||||||
# if no global property
|
# if no global property
|
||||||
|
@ -747,49 +741,52 @@ class Settings(object):
|
||||||
raise PropertiesOptionError(option_bag,
|
raise PropertiesOptionError(option_bag,
|
||||||
properties,
|
properties,
|
||||||
self,
|
self,
|
||||||
help_properties=calc_properties)
|
help_properties=calc_properties,
|
||||||
|
)
|
||||||
|
|
||||||
def validate_mandatory(self,
|
def validate_mandatory(self,
|
||||||
value,
|
value,
|
||||||
option_bag,
|
option_bag,
|
||||||
):
|
):
|
||||||
if 'mandatory' in option_bag.config_bag.properties:
|
"""verify if option is mandatory without value
|
||||||
values = option_bag.config_bag.context.get_values()
|
"""
|
||||||
if option_bag.option.impl_is_follower():
|
if 'mandatory' not in option_bag.config_bag.properties:
|
||||||
force_allow_empty_list = True
|
return
|
||||||
else:
|
values = option_bag.config_bag.context.get_values()
|
||||||
force_allow_empty_list = False
|
if not ('permissive' in option_bag.config_bag.properties and
|
||||||
if not ('permissive' in option_bag.config_bag.properties and
|
'mandatory' in option_bag.config_bag.permissives) and \
|
||||||
'mandatory' in option_bag.config_bag.permissives) and \
|
'mandatory' in option_bag.properties and values.isempty(option_bag,
|
||||||
'mandatory' in option_bag.properties and values.isempty(option_bag.option,
|
value,
|
||||||
value,
|
False,
|
||||||
force_allow_empty_list=force_allow_empty_list,
|
):
|
||||||
index=option_bag.index,
|
raise PropertiesOptionError(option_bag,
|
||||||
):
|
['mandatory'],
|
||||||
raise PropertiesOptionError(option_bag,
|
self,
|
||||||
['mandatory'],
|
)
|
||||||
self,
|
if 'empty' in option_bag.properties and values.isempty(option_bag,
|
||||||
)
|
value,
|
||||||
if 'empty' in option_bag.properties and values.isempty(option_bag.option,
|
True,
|
||||||
value,
|
):
|
||||||
force_allow_empty_list=True,
|
raise PropertiesOptionError(option_bag,
|
||||||
index=option_bag.index,
|
['empty'],
|
||||||
):
|
self,
|
||||||
raise PropertiesOptionError(option_bag,
|
)
|
||||||
['empty'],
|
|
||||||
self,
|
|
||||||
)
|
|
||||||
|
|
||||||
def validate_frozen(self,
|
def validate_frozen(self,
|
||||||
option_bag):
|
option_bag,
|
||||||
|
):
|
||||||
|
"""verify if option is frozen
|
||||||
|
"""
|
||||||
if option_bag.config_bag.properties and \
|
if option_bag.config_bag.properties and \
|
||||||
('everything_frozen' in option_bag.config_bag.properties or
|
('everything_frozen' in option_bag.config_bag.properties or
|
||||||
('frozen' in option_bag.config_bag.properties and 'frozen' in option_bag.properties)) and \
|
('frozen' in option_bag.config_bag.properties and \
|
||||||
|
'frozen' in option_bag.properties)) and \
|
||||||
not (('permissive' in option_bag.config_bag.properties) and
|
not (('permissive' in option_bag.config_bag.properties) and
|
||||||
'frozen' in option_bag.config_bag.permissives):
|
'frozen' in option_bag.config_bag.permissives):
|
||||||
raise PropertiesOptionError(option_bag,
|
raise PropertiesOptionError(option_bag,
|
||||||
['frozen'],
|
['frozen'],
|
||||||
self)
|
self,
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
#____________________________________________________________
|
#____________________________________________________________
|
||||||
# read only/read write
|
# read only/read write
|
||||||
|
@ -799,7 +796,10 @@ class Settings(object):
|
||||||
append,
|
append,
|
||||||
config_bag,
|
config_bag,
|
||||||
):
|
):
|
||||||
props = self._properties.get(None, {}).get(None, self.default_properties)
|
props = self.get_stored_properties(None,
|
||||||
|
None,
|
||||||
|
self.default_properties,
|
||||||
|
)
|
||||||
modified = False
|
modified = False
|
||||||
if remove & props:
|
if remove & props:
|
||||||
props = props - remove
|
props = props - remove
|
||||||
|
|
|
@ -207,7 +207,7 @@ class Requires(object):
|
||||||
else:
|
else:
|
||||||
act = 'hide'
|
act = 'hide'
|
||||||
inv_act = 'show'
|
inv_act = 'show'
|
||||||
if option.get_type() == 'choice':
|
if isinstance(option, ChoiceOption):
|
||||||
require_option = self.tiramisu_web.config.unrestraint.option(option_path)
|
require_option = self.tiramisu_web.config.unrestraint.option(option_path)
|
||||||
values = self.tiramisu_web.get_enum(require_option,
|
values = self.tiramisu_web.get_enum(require_option,
|
||||||
require_option.option.ismulti(),
|
require_option.option.ismulti(),
|
||||||
|
|
|
@ -15,39 +15,37 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
import weakref
|
from typing import Union, Optional, List, Any
|
||||||
from typing import Optional, Any, Callable
|
from .error import ConfigError
|
||||||
from .error import ConfigError, PropertiesOptionError
|
from .setting import owners, undefined, forbidden_owners, OptionBag
|
||||||
from .setting import owners, undefined, forbidden_owners, OptionBag, ConfigBag
|
from .autolib import Calculation
|
||||||
from .autolib import Calculation, carry_out_calculation, Params
|
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
|
|
||||||
|
|
||||||
class Values:
|
class Values:
|
||||||
"""The `Config`'s root is indeed in charge of the `Option()`'s values,
|
"""This class manage value (default value, stored value or calculated value
|
||||||
but the values are physicaly located here, in `Values`, wich is also
|
It's also responsible of a caching utility.
|
||||||
responsible of a caching utility.
|
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=too-many-public-methods
|
||||||
__slots__ = ('_values',
|
__slots__ = ('_values',
|
||||||
'_informations',
|
'_informations',
|
||||||
'__weakref__',
|
'__weakref__',
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
default_values=None,
|
default_values: Union[None, dict]=None,
|
||||||
):
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Initializes the values's dict.
|
Initializes the values's dict.
|
||||||
|
|
||||||
:param storage: where values or owners are stored
|
:param default_values: values stored by default for this object
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._informations = {}
|
self._informations = {}
|
||||||
# set default owner
|
# set default owner
|
||||||
if not default_values:
|
if not default_values:
|
||||||
self._values = {None: {None: [None, owners.user]}}
|
default_values = {None: {None: [None, owners.user]}}
|
||||||
else:
|
self._values = default_values
|
||||||
self._values = default_values
|
|
||||||
|
|
||||||
#______________________________________________________________________
|
#______________________________________________________________________
|
||||||
# get value
|
# get value
|
||||||
|
@ -61,17 +59,13 @@ class Values:
|
||||||
"""
|
"""
|
||||||
# try to retrive value in cache
|
# try to retrive value in cache
|
||||||
setting_properties = option_bag.config_bag.properties
|
setting_properties = option_bag.config_bag.properties
|
||||||
cache = option_bag.config_bag.context._impl_values_cache
|
cache = option_bag.config_bag.context.get_values_cache()
|
||||||
is_cached, value, validated = cache.getcache(option_bag.path,
|
is_cached, value, validated = cache.getcache(option_bag,
|
||||||
option_bag.config_bag.expiration_time,
|
'values',
|
||||||
option_bag.index,
|
|
||||||
setting_properties,
|
|
||||||
option_bag.properties,
|
|
||||||
'value',
|
|
||||||
)
|
)
|
||||||
# no cached value so get value
|
# no cached value so get value
|
||||||
if not is_cached:
|
if not is_cached:
|
||||||
value = self.getvalue(option_bag)
|
value = self.get_value(option_bag)
|
||||||
# validates and warns value
|
# validates and warns value
|
||||||
if not validated:
|
if not validated:
|
||||||
validate = option_bag.option.impl_validate(value,
|
validate = option_bag.option.impl_validate(value,
|
||||||
|
@ -85,12 +79,9 @@ class Values:
|
||||||
)
|
)
|
||||||
# set value to cache
|
# set value to cache
|
||||||
if not is_cached:
|
if not is_cached:
|
||||||
cache.setcache(option_bag.path,
|
cache.setcache(option_bag,
|
||||||
option_bag.index,
|
|
||||||
value,
|
value,
|
||||||
option_bag.properties,
|
validated=validate,
|
||||||
setting_properties,
|
|
||||||
validate,
|
|
||||||
)
|
)
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
# return a copy, so value cannot be modified
|
# return a copy, so value cannot be modified
|
||||||
|
@ -98,81 +89,28 @@ class Values:
|
||||||
# and return it
|
# and return it
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def force_to_metaconfig(self, option_bag):
|
def get_value(self,
|
||||||
# force_metaconfig_on_freeze in config => to metaconfig
|
option_bag: OptionBag,
|
||||||
# force_metaconfig_on_freeze in option + config is kernelconfig => to metaconfig
|
) -> Any:
|
||||||
settings = option_bag.config_bag.context.get_settings()
|
"""actually retrieves the stored value or the default value (value modified by user)
|
||||||
if 'force_metaconfig_on_freeze' in option_bag.properties:
|
|
||||||
settings = option_bag.config_bag.context.get_settings()
|
|
||||||
if 'force_metaconfig_on_freeze' in option_bag.option.impl_getproperties() and \
|
|
||||||
not settings._properties.get(option_bag.path, {}).get(None, frozenset()):
|
|
||||||
# if force_metaconfig_on_freeze is only in option (not in config)
|
|
||||||
return option_bag.config_bag.context.impl_type == 'config'
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _do_value_list(self,
|
|
||||||
value: Any,
|
|
||||||
option_bag: OptionBag,
|
|
||||||
):
|
|
||||||
ret = []
|
|
||||||
for val in value:
|
|
||||||
if isinstance(val, (list, tuple)):
|
|
||||||
ret.append(self._do_value_list(val, option_bag))
|
|
||||||
elif isinstance(val, Calculation):
|
|
||||||
ret.append(val.execute(option_bag))
|
|
||||||
else:
|
|
||||||
ret.append(val)
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def getvalue(self,
|
|
||||||
option_bag,
|
|
||||||
):
|
|
||||||
"""actually retrieves the value
|
|
||||||
|
|
||||||
:param path: the path of the `Option`
|
|
||||||
:param index: index for a follower `Option`
|
|
||||||
|
|
||||||
:returns: value
|
:returns: value
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# get owner and value from store
|
# get owner and value from store
|
||||||
# index allowed only for follower
|
default_value = [undefined, owners.default]
|
||||||
index = option_bag.index
|
value, owner = self._values.get(option_bag.path, {}).get(option_bag.index, default_value)
|
||||||
is_follower = option_bag.option.impl_is_follower()
|
|
||||||
if index is None or not is_follower:
|
|
||||||
_index = None
|
|
||||||
else:
|
|
||||||
_index = index
|
|
||||||
value, owner = self._values.get(option_bag.path, {}).get(_index, [undefined, owners.default])
|
|
||||||
if owner == owners.default or \
|
if owner == owners.default or \
|
||||||
('frozen' in option_bag.properties and \
|
('frozen' in option_bag.properties and \
|
||||||
('force_default_on_freeze' in option_bag.properties or self.force_to_metaconfig(option_bag))):
|
('force_default_on_freeze' in option_bag.properties or \
|
||||||
value = self.getdefaultvalue(option_bag)
|
self.check_force_to_metaconfig(option_bag))):
|
||||||
else:
|
# the value is a default value
|
||||||
value = self.calc_value(option_bag, value)
|
# get it
|
||||||
|
value = self.get_default_value(option_bag)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def calc_value(self,
|
def get_default_value(self,
|
||||||
option_bag,
|
option_bag: OptionBag,
|
||||||
value,
|
) -> Any:
|
||||||
reset_cache=True):
|
|
||||||
if isinstance(value, Calculation):
|
|
||||||
try:
|
|
||||||
value = value.execute(option_bag)
|
|
||||||
except ConfigError as err:
|
|
||||||
msg = _(f'error when calculating "{option_bag.option.impl_get_display_name()}": {err} : {option_bag.path}')
|
|
||||||
raise ConfigError(msg) from err
|
|
||||||
elif isinstance(value, (list, tuple)):
|
|
||||||
value = self._do_value_list(value, option_bag)
|
|
||||||
if reset_cache:
|
|
||||||
self.calculate_reset_cache(option_bag, value)
|
|
||||||
return value
|
|
||||||
|
|
||||||
def getdefaultvalue(self,
|
|
||||||
option_bag,
|
|
||||||
):
|
|
||||||
"""get default value:
|
"""get default value:
|
||||||
- get parents config value or
|
- get parents config value or
|
||||||
- get calculated value or
|
- get calculated value or
|
||||||
|
@ -183,45 +121,84 @@ class Values:
|
||||||
# retrieved value from parent config
|
# retrieved value from parent config
|
||||||
return moption_bag.config_bag.context.get_values().get_cached_value(moption_bag)
|
return moption_bag.config_bag.context.get_values().get_cached_value(moption_bag)
|
||||||
|
|
||||||
# now try to get default value:
|
# now try to get calculated value:
|
||||||
value = self.calc_value(option_bag,
|
value = self.get_calculated_value(option_bag,
|
||||||
option_bag.option.impl_getdefault(),
|
option_bag.option.impl_getdefault(),
|
||||||
)
|
)
|
||||||
if option_bag.index is not None and isinstance(value, (list, tuple)):
|
if option_bag.index is not None and isinstance(value, (list, tuple)) \
|
||||||
if value and option_bag.option.impl_is_submulti():
|
and (not option_bag.option.impl_is_submulti() or \
|
||||||
# first index is a list, assume other data are list too
|
not value or isinstance(value[0], list)):
|
||||||
if isinstance(value[0], list):
|
# if index (so slave), must return good value for this index
|
||||||
# if index, must return good value for this index
|
# for submulti, first index is a list, assume other data are list too
|
||||||
if len(value) > option_bag.index:
|
if len(value) > option_bag.index:
|
||||||
value = value[option_bag.index]
|
value = value[option_bag.index]
|
||||||
else:
|
else:
|
||||||
# no value for this index, retrieve default multi value
|
# no value for this index, retrieve default multi value
|
||||||
# default_multi is already a list for submulti
|
# default_multi is already a list for submulti
|
||||||
value = self.calc_value(option_bag,
|
value = self.get_calculated_value(option_bag,
|
||||||
option_bag.option.impl_getdefault_multi())
|
option_bag.option.impl_getdefault_multi(),
|
||||||
elif option_bag.option.impl_is_multi():
|
)
|
||||||
# if index, must return good value for this index
|
|
||||||
if len(value) > option_bag.index:
|
|
||||||
value = value[option_bag.index]
|
|
||||||
else:
|
|
||||||
# no value for this index, retrieve default multi value
|
|
||||||
# default_multi is already a list for submulti
|
|
||||||
value = self.calc_value(option_bag,
|
|
||||||
option_bag.option.impl_getdefault_multi())
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def calculate_reset_cache(self,
|
def get_calculated_value(self,
|
||||||
option_bag,
|
option_bag,
|
||||||
value):
|
value,
|
||||||
if not 'expire' in option_bag.properties:
|
reset_cache=True,
|
||||||
return
|
) -> Any:
|
||||||
cache = option_bag.config_bag.context._impl_values_cache
|
"""value could be a calculation, in this case do calculation
|
||||||
is_cache, cache_value, validated = cache.getcache(option_bag.path,
|
"""
|
||||||
None,
|
if isinstance(value, Calculation):
|
||||||
option_bag.index,
|
try:
|
||||||
option_bag.config_bag.properties,
|
value = value.execute(option_bag)
|
||||||
option_bag.properties,
|
except ConfigError as err:
|
||||||
'value')
|
msg = _(f'error when calculating "{option_bag.option.impl_get_display_name()}": '
|
||||||
|
f'{err} : {option_bag.path}')
|
||||||
|
raise ConfigError(msg) from err
|
||||||
|
elif isinstance(value, list):
|
||||||
|
# if value is a list, do subcalculation
|
||||||
|
for idx, val in enumerate(value):
|
||||||
|
value[idx] = self.get_calculated_value(option_bag,
|
||||||
|
val,
|
||||||
|
reset_cache=False,
|
||||||
|
)
|
||||||
|
if reset_cache:
|
||||||
|
self.reset_cache_after_calculation(option_bag,
|
||||||
|
value,
|
||||||
|
)
|
||||||
|
return value
|
||||||
|
|
||||||
|
#______________________________________________________________________
|
||||||
|
def check_force_to_metaconfig(self,
|
||||||
|
option_bag: OptionBag,
|
||||||
|
) -> bool:
|
||||||
|
"""Check if the value must be retrieve from parent metaconfig or not
|
||||||
|
"""
|
||||||
|
# force_metaconfig_on_freeze is set to an option and context is a kernelconfig
|
||||||
|
# => to metaconfig
|
||||||
|
# force_metaconfig_on_freeze is set *explicitly* to an option and context is a
|
||||||
|
# kernelmetaconfig => to sub metaconfig
|
||||||
|
if 'force_metaconfig_on_freeze' in option_bag.properties:
|
||||||
|
settings = option_bag.config_bag.context.get_settings()
|
||||||
|
if option_bag.config_bag.context.impl_type == 'config':
|
||||||
|
return True
|
||||||
|
# it's a not a config, force to metaconfig only in *explicitly* set
|
||||||
|
return 'force_metaconfig_on_freeze' in settings.get_stored_properties(option_bag.path,
|
||||||
|
option_bag.index,
|
||||||
|
frozenset(),
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def reset_cache_after_calculation(self,
|
||||||
|
option_bag,
|
||||||
|
value,
|
||||||
|
):
|
||||||
|
"""if value is modification after calculation, invalid cache
|
||||||
|
"""
|
||||||
|
cache = option_bag.config_bag.context.get_values_cache()
|
||||||
|
is_cache, cache_value, _ = cache.getcache(option_bag,
|
||||||
|
'values',
|
||||||
|
expiration=False,
|
||||||
|
)
|
||||||
if not is_cache or cache_value == value:
|
if not is_cache or cache_value == value:
|
||||||
# calculation return same value as previous value,
|
# calculation return same value as previous value,
|
||||||
# so do not invalidate cache
|
# so do not invalidate cache
|
||||||
|
@ -232,30 +209,47 @@ class Values:
|
||||||
self._set_force_value_suffix(option_bag)
|
self._set_force_value_suffix(option_bag)
|
||||||
|
|
||||||
def isempty(self,
|
def isempty(self,
|
||||||
opt,
|
option_bag: OptionBag,
|
||||||
value,
|
value: Any,
|
||||||
force_allow_empty_list=False,
|
force_allow_empty_list: bool,
|
||||||
index=None):
|
) -> bool:
|
||||||
"convenience method to know if an option is empty"
|
"""convenience method to know if an option is empty
|
||||||
empty = opt._empty
|
"""
|
||||||
if index in [None, undefined] and opt.impl_is_multi():
|
if option_bag.index is None and option_bag.option.impl_is_submulti():
|
||||||
isempty = value is None or (isinstance(value, list) and not force_allow_empty_list and value == []) or \
|
# index is not set
|
||||||
(isinstance(value, list) and None in value) or empty in value
|
isempty = True
|
||||||
|
for val in value:
|
||||||
|
isempty = self._isempty_multi(val, force_allow_empty_list)
|
||||||
|
if isempty:
|
||||||
|
break
|
||||||
|
elif (option_bag.index is None or \
|
||||||
|
(option_bag.index is not None and option_bag.option.impl_is_submulti())) and \
|
||||||
|
option_bag.option.impl_is_multi():
|
||||||
|
# it's a single list
|
||||||
|
isempty = self._isempty_multi(value, force_allow_empty_list)
|
||||||
else:
|
else:
|
||||||
isempty = value is None or value == empty or (opt.impl_is_submulti() and value == [])
|
isempty = value is None or value == ''
|
||||||
return isempty
|
return isempty
|
||||||
|
|
||||||
|
def _isempty_multi(self,
|
||||||
|
value: Any,
|
||||||
|
force_allow_empty_list: bool,
|
||||||
|
) -> bool:
|
||||||
|
return (not force_allow_empty_list and value == []) or None in value or '' in value
|
||||||
|
|
||||||
#______________________________________________________________________
|
#______________________________________________________________________
|
||||||
# set value
|
# set value
|
||||||
def set_value(self,
|
def set_value(self,
|
||||||
option_bag,
|
option_bag: OptionBag,
|
||||||
value,
|
value: Any,
|
||||||
):
|
) -> None:
|
||||||
context = option_bag.config_bag.context
|
"""set value to option
|
||||||
|
"""
|
||||||
owner = self.get_context_owner()
|
owner = self.get_context_owner()
|
||||||
if 'validator' in option_bag.config_bag.properties:
|
if 'validator' in option_bag.config_bag.properties:
|
||||||
self.setvalue_validation(value,
|
self.setvalue_validation(value,
|
||||||
option_bag)
|
option_bag,
|
||||||
|
)
|
||||||
|
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
# copy
|
# copy
|
||||||
|
@ -265,33 +259,35 @@ class Values:
|
||||||
owner,
|
owner,
|
||||||
)
|
)
|
||||||
setting_properties = option_bag.config_bag.properties
|
setting_properties = option_bag.config_bag.properties
|
||||||
validator = 'validator' in setting_properties and 'demoting_error_warning' not in setting_properties
|
validator = 'validator' in setting_properties and \
|
||||||
|
'demoting_error_warning' not in setting_properties
|
||||||
if validator:
|
if validator:
|
||||||
cache = option_bag.config_bag.context._impl_values_cache
|
cache = option_bag.config_bag.context.get_values_cache()
|
||||||
cache.setcache(option_bag.path,
|
cache.setcache(option_bag,
|
||||||
option_bag.index,
|
|
||||||
value,
|
value,
|
||||||
option_bag.properties,
|
validated=validator,
|
||||||
setting_properties,
|
)
|
||||||
validator)
|
|
||||||
if 'force_store_value' in setting_properties and option_bag.option.impl_is_leader():
|
if 'force_store_value' in setting_properties and option_bag.option.impl_is_leader():
|
||||||
option_bag.option.impl_get_leadership().follower_force_store_value(self,
|
leader = option_bag.option.impl_get_leadership()
|
||||||
value,
|
leader.follower_force_store_value(value,
|
||||||
option_bag,
|
option_bag.config_bag,
|
||||||
owners.forced,
|
owners.forced,
|
||||||
)
|
)
|
||||||
|
|
||||||
def setvalue_validation(self,
|
def setvalue_validation(self,
|
||||||
value,
|
value,
|
||||||
option_bag,
|
option_bag,
|
||||||
):
|
):
|
||||||
|
"""validate value before set value
|
||||||
|
"""
|
||||||
settings = option_bag.config_bag.context.get_settings()
|
settings = option_bag.config_bag.context.get_settings()
|
||||||
# First validate properties with this value
|
# First validate properties with this value
|
||||||
opt = option_bag.option
|
opt = option_bag.option
|
||||||
settings.validate_frozen(option_bag)
|
settings.validate_frozen(option_bag)
|
||||||
val = self.calc_value(option_bag,
|
val = self.get_calculated_value(option_bag,
|
||||||
value,
|
value,
|
||||||
False,)
|
False,
|
||||||
|
)
|
||||||
settings.validate_mandatory(val,
|
settings.validate_mandatory(val,
|
||||||
option_bag,
|
option_bag,
|
||||||
)
|
)
|
||||||
|
@ -320,25 +316,25 @@ class Values:
|
||||||
)
|
)
|
||||||
self._set_force_value_suffix(option_bag)
|
self._set_force_value_suffix(option_bag)
|
||||||
|
|
||||||
def reduce_index(self,
|
|
||||||
path,
|
|
||||||
index):
|
|
||||||
self._values[path][index - 1] = self._values[path].pop(index)
|
|
||||||
|
|
||||||
def set_storage_value(self,
|
def set_storage_value(self,
|
||||||
path,
|
path,
|
||||||
index,
|
index,
|
||||||
value,
|
value,
|
||||||
owner,
|
owner,
|
||||||
):
|
):
|
||||||
|
"""set a value
|
||||||
|
"""
|
||||||
self._values.setdefault(path, {})[index] = [value, owner]
|
self._values.setdefault(path, {})[index] = [value, owner]
|
||||||
|
|
||||||
def _set_force_value_suffix(self,
|
def _set_force_value_suffix(self, option_bag: OptionBag) -> None:
|
||||||
option_bag: OptionBag,
|
""" force store value for an option for suffixes
|
||||||
) -> None:
|
"""
|
||||||
|
# pylint: disable=too-many-locals
|
||||||
if 'force_store_value' not in option_bag.config_bag.properties:
|
if 'force_store_value' not in option_bag.config_bag.properties:
|
||||||
return
|
return
|
||||||
for woption in option_bag.option._get_suffixes_dependencies():
|
|
||||||
|
for woption in option_bag.option._get_suffixes_dependencies(): # pylint: disable=protected-access
|
||||||
|
# options from dependencies are weakref
|
||||||
option = woption()
|
option = woption()
|
||||||
force_store_options = []
|
force_store_options = []
|
||||||
for coption in option.get_children_recursively(None,
|
for coption in option.get_children_recursively(None,
|
||||||
|
@ -350,10 +346,10 @@ class Values:
|
||||||
if not force_store_options:
|
if not force_store_options:
|
||||||
continue
|
continue
|
||||||
rootpath = option.impl_getpath()
|
rootpath = option.impl_getpath()
|
||||||
settings = option_bag.config_bag.context.get_settings()
|
|
||||||
for suffix in option.get_suffixes(option_bag.config_bag):
|
for suffix in option.get_suffixes(option_bag.config_bag):
|
||||||
for coption in force_store_options:
|
for coption in force_store_options:
|
||||||
subpaths = [rootpath] + coption.impl_getpath()[len(rootpath) + 1:].split('.')[:-1]
|
subpaths = [rootpath] + \
|
||||||
|
coption.impl_getpath()[len(rootpath) + 1:].split('.')[:-1]
|
||||||
path_suffix = option.convert_suffix_to_path(suffix)
|
path_suffix = option.convert_suffix_to_path(suffix)
|
||||||
subpath = '.'.join([subp + path_suffix for subp in subpaths])
|
subpath = '.'.join([subp + path_suffix for subp in subpaths])
|
||||||
doption = coption.to_dynoption(subpath,
|
doption = coption.to_dynoption(subpath,
|
||||||
|
@ -367,7 +363,7 @@ class Values:
|
||||||
option_bag.config_bag,
|
option_bag.config_bag,
|
||||||
properties=frozenset(),
|
properties=frozenset(),
|
||||||
)
|
)
|
||||||
indexes = range(len(self.getvalue(loption_bag)))
|
indexes = range(len(self.get_value(loption_bag)))
|
||||||
else:
|
else:
|
||||||
indexes = [None]
|
indexes = [None]
|
||||||
for index in indexes:
|
for index in indexes:
|
||||||
|
@ -375,7 +371,8 @@ class Values:
|
||||||
index,
|
index,
|
||||||
option_bag.config_bag,
|
option_bag.config_bag,
|
||||||
)
|
)
|
||||||
self._values.setdefault(coption_bag.path, {})[index] = [self.getvalue(coption_bag), owners.forced]
|
default_value = [self.get_value(coption_bag), owners.forced]
|
||||||
|
self._values.setdefault(coption_bag.path, {})[index] = default_value
|
||||||
|
|
||||||
def _get_modified_parent(self,
|
def _get_modified_parent(self,
|
||||||
option_bag: OptionBag,
|
option_bag: OptionBag,
|
||||||
|
@ -398,8 +395,9 @@ class Values:
|
||||||
# remove force_metaconfig_on_freeze only if option in metaconfig
|
# remove force_metaconfig_on_freeze only if option in metaconfig
|
||||||
# hasn't force_metaconfig_on_freeze properties
|
# hasn't force_metaconfig_on_freeze properties
|
||||||
ori_properties = doption_bag.properties
|
ori_properties = doption_bag.properties
|
||||||
doption_bag.properties = doption_bag.config_bag.context.get_settings().getproperties(doption_bag)
|
settings = doption_bag.config_bag.context.get_settings()
|
||||||
if not self.force_to_metaconfig(doption_bag):
|
doption_bag.properties = settings.getproperties(doption_bag)
|
||||||
|
if not self.check_force_to_metaconfig(doption_bag):
|
||||||
doption_bag.properties = ori_properties - {'force_metaconfig_on_freeze'}
|
doption_bag.properties = ori_properties - {'force_metaconfig_on_freeze'}
|
||||||
else:
|
else:
|
||||||
doption_bag.properties = ori_properties
|
doption_bag.properties = ori_properties
|
||||||
|
@ -416,11 +414,15 @@ class Values:
|
||||||
# owner
|
# owner
|
||||||
|
|
||||||
def is_default_owner(self,
|
def is_default_owner(self,
|
||||||
option_bag,
|
option_bag: OptionBag,
|
||||||
validate_meta=True):
|
validate_meta: bool=True,
|
||||||
|
) -> bool:
|
||||||
|
"""is default owner for an option
|
||||||
|
"""
|
||||||
return self.getowner(option_bag,
|
return self.getowner(option_bag,
|
||||||
validate_meta=validate_meta,
|
validate_meta=validate_meta,
|
||||||
only_default=True) == owners.default
|
only_default=True,
|
||||||
|
) == owners.default
|
||||||
|
|
||||||
def hasvalue(self,
|
def hasvalue(self,
|
||||||
path,
|
path,
|
||||||
|
@ -432,7 +434,7 @@ class Values:
|
||||||
has_path = path in self._values
|
has_path = path in self._values
|
||||||
if index is None:
|
if index is None:
|
||||||
return has_path
|
return has_path
|
||||||
elif has_path:
|
if has_path:
|
||||||
return index in self._values[path]
|
return index in self._values[path]
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -468,14 +470,18 @@ class Values:
|
||||||
else:
|
else:
|
||||||
owner = owners.default
|
owner = owners.default
|
||||||
else:
|
else:
|
||||||
owner = self._values.get(option_bag.path, {}).get(option_bag.index, [undefined, owners.default])[1]
|
owner = self._values.get(option_bag.path, {}).get(option_bag.index,
|
||||||
if validate_meta is not False and (owner is owners.default or \
|
[undefined, owners.default],
|
||||||
'frozen' in option_bag.properties and 'force_metaconfig_on_freeze' in option_bag.properties):
|
)[1]
|
||||||
|
if validate_meta is not False and (owner is owners.default or
|
||||||
|
'frozen' in option_bag.properties and
|
||||||
|
'force_metaconfig_on_freeze' in option_bag.properties):
|
||||||
moption_bag = self._get_modified_parent(option_bag)
|
moption_bag = self._get_modified_parent(option_bag)
|
||||||
if moption_bag is not None:
|
if moption_bag is not None:
|
||||||
owner = moption_bag.config_bag.context.get_values().getowner(moption_bag,
|
values = moption_bag.config_bag.context.get_values()
|
||||||
only_default=only_default,
|
owner = values.getowner(moption_bag,
|
||||||
)
|
only_default=only_default,
|
||||||
|
)
|
||||||
elif 'force_metaconfig_on_freeze' in option_bag.properties:
|
elif 'force_metaconfig_on_freeze' in option_bag.properties:
|
||||||
return owners.default
|
return owners.default
|
||||||
return owner
|
return owner
|
||||||
|
@ -487,32 +493,28 @@ class Values:
|
||||||
"""
|
"""
|
||||||
sets a owner to an option
|
sets a owner to an option
|
||||||
|
|
||||||
:param opt: the `option.Option` object
|
:param option_bag: the `OptionBag` object
|
||||||
:param owner: a valid owner, that is a `setting.owners.Owner` object
|
:param owner: a valid owner, that is a `setting.owners.Owner` object
|
||||||
"""
|
"""
|
||||||
opt = option_bag.option
|
|
||||||
if opt.impl_is_symlinkoption():
|
|
||||||
raise ConfigError(_("can't set owner for the symlinkoption \"{}\""
|
|
||||||
"").format(opt.impl_get_display_name()))
|
|
||||||
if owner in forbidden_owners:
|
if owner in forbidden_owners:
|
||||||
raise ValueError(_('set owner "{0}" is forbidden').format(str(owner)))
|
raise ValueError(_('set owner "{0}" is forbidden').format(str(owner)))
|
||||||
|
|
||||||
if not self.hasvalue(option_bag.path, option_bag.index):
|
if not self.hasvalue(option_bag.path, option_bag.index):
|
||||||
raise ConfigError(_('no value for {0} cannot change owner to {1}'
|
raise ConfigError(_(f'no value for {option_bag.path} cannot change owner to {owner}'))
|
||||||
'').format(option_bag.path, owner))
|
|
||||||
option_bag.config_bag.context.get_settings().validate_frozen(option_bag)
|
option_bag.config_bag.context.get_settings().validate_frozen(option_bag)
|
||||||
self._values[option_bag.path][option_bag.index][1] = owner
|
self._values[option_bag.path][option_bag.index][1] = owner
|
||||||
#______________________________________________________________________
|
#______________________________________________________________________
|
||||||
# reset
|
# reset
|
||||||
|
|
||||||
def reset(self,
|
def reset(self, option_bag: OptionBag) -> None:
|
||||||
option_bag):
|
"""reset value for an option
|
||||||
|
"""
|
||||||
context = option_bag.config_bag.context
|
context = option_bag.config_bag.context
|
||||||
hasvalue = self.hasvalue(option_bag.path)
|
hasvalue = self.hasvalue(option_bag.path)
|
||||||
setting_properties = option_bag.config_bag.properties
|
setting_properties = option_bag.config_bag.properties
|
||||||
|
|
||||||
if hasvalue and 'validator' in option_bag.config_bag.properties:
|
if hasvalue and 'validator' in option_bag.config_bag.properties:
|
||||||
fake_context = context._gen_fake_values()
|
fake_context = context.gen_fake_values()
|
||||||
config_bag = option_bag.config_bag.copy()
|
config_bag = option_bag.config_bag.copy()
|
||||||
config_bag.remove_validation()
|
config_bag.remove_validation()
|
||||||
config_bag.context = fake_context
|
config_bag.context = fake_context
|
||||||
|
@ -521,16 +523,17 @@ class Values:
|
||||||
fake_value = fake_context.get_values()
|
fake_value = fake_context.get_values()
|
||||||
fake_value.reset(soption_bag)
|
fake_value.reset(soption_bag)
|
||||||
soption_bag.config_bag.properties = option_bag.config_bag.properties
|
soption_bag.config_bag.properties = option_bag.config_bag.properties
|
||||||
value = fake_value.getdefaultvalue(soption_bag)
|
value = fake_value.get_default_value(soption_bag)
|
||||||
fake_value.setvalue_validation(value,
|
fake_value.setvalue_validation(value,
|
||||||
soption_bag)
|
soption_bag,
|
||||||
|
)
|
||||||
opt = option_bag.option
|
opt = option_bag.option
|
||||||
if opt.impl_is_leader():
|
if opt.impl_is_leader():
|
||||||
opt.impl_get_leadership().reset(self,
|
opt.impl_get_leadership().reset(option_bag.config_bag)
|
||||||
option_bag)
|
|
||||||
if hasvalue:
|
if hasvalue:
|
||||||
if 'force_store_value' in option_bag.config_bag.properties and 'force_store_value' in option_bag.properties:
|
if 'force_store_value' in option_bag.config_bag.properties and \
|
||||||
value = self.getdefaultvalue(option_bag)
|
'force_store_value' in option_bag.properties:
|
||||||
|
value = self.get_default_value(option_bag)
|
||||||
|
|
||||||
self._setvalue(option_bag,
|
self._setvalue(option_bag,
|
||||||
value,
|
value,
|
||||||
|
@ -544,72 +547,89 @@ class Values:
|
||||||
context.reset_cache(option_bag)
|
context.reset_cache(option_bag)
|
||||||
if 'force_store_value' in setting_properties and option_bag.option.impl_is_leader():
|
if 'force_store_value' in setting_properties and option_bag.option.impl_is_leader():
|
||||||
if value is None:
|
if value is None:
|
||||||
value = self.getdefaultvalue(option_bag)
|
value = self.get_default_value(option_bag)
|
||||||
option_bag.option.impl_get_leadership().follower_force_store_value(self,
|
leader = option_bag.option.impl_get_leadership()
|
||||||
value,
|
leader.follower_force_store_value(value,
|
||||||
option_bag,
|
option_bag.config_bag,
|
||||||
owners.forced)
|
owners.forced,
|
||||||
|
)
|
||||||
|
#______________________________________________________________________
|
||||||
|
# Follower
|
||||||
|
|
||||||
def get_max_length(self, path):
|
def get_max_length(self, path: str) -> int:
|
||||||
|
"""get max index for a follower and determine the length of the follower
|
||||||
|
"""
|
||||||
values = self._values.get(path, {})
|
values = self._values.get(path, {})
|
||||||
if values:
|
if values:
|
||||||
return max(values) + 1
|
return max(values) + 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def reset_follower(self,
|
def reset_follower(self,
|
||||||
option_bag):
|
option_bag: OptionBag,
|
||||||
if self.hasvalue(option_bag.path,
|
) -> None:
|
||||||
index=option_bag.index):
|
"""reset value for a follower
|
||||||
context = option_bag.config_bag.context
|
"""
|
||||||
setting_properties = option_bag.config_bag.properties
|
if not self.hasvalue(option_bag.path,
|
||||||
if 'validator' in setting_properties:
|
index=option_bag.index,
|
||||||
fake_context = context._gen_fake_values()
|
):
|
||||||
fake_value = fake_context.get_values()
|
return
|
||||||
config_bag = option_bag.config_bag.copy()
|
context = option_bag.config_bag.context
|
||||||
config_bag.remove_validation()
|
setting_properties = option_bag.config_bag.properties
|
||||||
config_bag.context = fake_context
|
if 'validator' in setting_properties:
|
||||||
soption_bag = option_bag.copy()
|
fake_context = context.gen_fake_values()
|
||||||
soption_bag.config_bag = config_bag
|
fake_value = fake_context.get_values()
|
||||||
fake_value.reset_follower(soption_bag)
|
config_bag = option_bag.config_bag.copy()
|
||||||
value = fake_value.getdefaultvalue(soption_bag)
|
config_bag.remove_validation()
|
||||||
fake_value.setvalue_validation(value,
|
config_bag.context = fake_context
|
||||||
soption_bag)
|
soption_bag = option_bag.copy()
|
||||||
if 'force_store_value' in setting_properties and 'force_store_value' in option_bag.properties:
|
soption_bag.config_bag = config_bag
|
||||||
value = self.getdefaultvalue(option_bag)
|
fake_value.reset_follower(soption_bag)
|
||||||
|
value = fake_value.get_default_value(soption_bag)
|
||||||
|
fake_value.setvalue_validation(value,
|
||||||
|
soption_bag)
|
||||||
|
if 'force_store_value' in setting_properties and \
|
||||||
|
'force_store_value' in option_bag.properties:
|
||||||
|
value = self.get_default_value(option_bag)
|
||||||
|
|
||||||
self._setvalue(option_bag,
|
self._setvalue(option_bag,
|
||||||
value,
|
value,
|
||||||
owners.forced,
|
owners.forced,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.resetvalue_index(option_bag.path,
|
self.resetvalue_index(option_bag)
|
||||||
option_bag.index,
|
context.reset_cache(option_bag)
|
||||||
)
|
|
||||||
context.reset_cache(option_bag)
|
|
||||||
|
|
||||||
def resetvalue_index(self,
|
def resetvalue_index(self, option_bag: OptionBag) -> None:
|
||||||
path,
|
"""reset a value for a follower at an index
|
||||||
index,
|
"""
|
||||||
):
|
if option_bag.path in self._values and option_bag.index in self._values[option_bag.path]:
|
||||||
if path in self._values and index in self._values[path]:
|
del self._values[option_bag.path][option_bag.index]
|
||||||
del self._values[path][index]
|
|
||||||
|
def reduce_index(self, option_bag: OptionBag) -> None:
|
||||||
|
"""reduce follower's value from a specified index
|
||||||
|
"""
|
||||||
|
self.resetvalue_index(option_bag)
|
||||||
|
for index in range(option_bag.index + 1, self.get_max_length(option_bag.path)):
|
||||||
|
if self.hasvalue(option_bag.path,
|
||||||
|
index,
|
||||||
|
):
|
||||||
|
self._values[option_bag.path][index - 1] = self._values[option_bag.path].pop(index)
|
||||||
|
|
||||||
def reset_leadership(self,
|
def reset_leadership(self,
|
||||||
option_bag: OptionBag,
|
option_bag: OptionBag,
|
||||||
leadership_option_bag: OptionBag,
|
leadership_option_bag: OptionBag,
|
||||||
index: int,
|
index: int,
|
||||||
):
|
) -> None:
|
||||||
|
"""reset leadershop from an index
|
||||||
|
"""
|
||||||
current_value = self.get_cached_value(option_bag)
|
current_value = self.get_cached_value(option_bag)
|
||||||
length = len(current_value)
|
length = len(current_value)
|
||||||
if index >= length:
|
if index >= length:
|
||||||
raise IndexError(_('index {} is greater than the length {} '
|
raise IndexError(_('index {index} is greater than the length {length} '
|
||||||
'for option "{}"').format(index,
|
'for option "{option_bag.option.impl_get_display_name()}"'))
|
||||||
length,
|
|
||||||
option_bag.option.impl_get_display_name()))
|
|
||||||
current_value.pop(index)
|
current_value.pop(index)
|
||||||
leadership_option_bag.option.pop(self,
|
leadership_option_bag.option.pop(index,
|
||||||
index,
|
option_bag.config_bag,
|
||||||
option_bag,
|
|
||||||
)
|
)
|
||||||
self.set_value(option_bag,
|
self.set_value(option_bag,
|
||||||
current_value,
|
current_value,
|
||||||
|
@ -619,7 +639,6 @@ class Values:
|
||||||
# information
|
# information
|
||||||
|
|
||||||
def set_information(self,
|
def set_information(self,
|
||||||
config_bag,
|
|
||||||
option_bag,
|
option_bag,
|
||||||
key,
|
key,
|
||||||
value,
|
value,
|
||||||
|
@ -634,55 +653,62 @@ class Values:
|
||||||
else:
|
else:
|
||||||
path = option_bag.path
|
path = option_bag.path
|
||||||
self._informations.setdefault(path, {})[key] = value
|
self._informations.setdefault(path, {})[key] = value
|
||||||
if path is not None:
|
if path is None:
|
||||||
for option in option_bag.option.get_dependencies_information(itself=True):
|
return
|
||||||
config_bag.context.reset_cache(option_bag)
|
if key in option_bag.option.get_dependencies_information(itself=True):
|
||||||
|
option_bag.config_bag.context.reset_cache(option_bag)
|
||||||
|
|
||||||
def get_information(self,
|
def get_information(self,
|
||||||
config_bag,
|
|
||||||
option_bag,
|
option_bag,
|
||||||
key,
|
name,
|
||||||
default,
|
default,
|
||||||
):
|
):
|
||||||
"""retrieves one information's item
|
"""retrieves one information's item
|
||||||
|
|
||||||
:param key: the item string (ex: "help")
|
:param name: the item string (ex: "help")
|
||||||
"""
|
"""
|
||||||
if option_bag is None:
|
if option_bag is None:
|
||||||
path = None
|
path = None
|
||||||
else:
|
else:
|
||||||
path = option_bag.path
|
path = option_bag.path
|
||||||
try:
|
try:
|
||||||
return self._informations[path][key]
|
return self._informations[path][name]
|
||||||
except KeyError as err:
|
except KeyError as err:
|
||||||
if option_bag:
|
if option_bag:
|
||||||
return option_bag.option.impl_get_information(key, default)
|
return option_bag.option.impl_get_information(name, default)
|
||||||
if default is not undefined:
|
if default is not undefined:
|
||||||
return default
|
return default
|
||||||
raise ValueError(_("information's item not found: {0}").format(key))
|
raise ValueError(_("information's item not found: {0}").format(name)) from err
|
||||||
|
|
||||||
def del_information(self,
|
def del_information(self,
|
||||||
key,
|
key: Any,
|
||||||
raises=True,
|
raises: bool=True,
|
||||||
path=None,
|
path: str=None,
|
||||||
):
|
):
|
||||||
|
"""delete information for a specified key
|
||||||
|
"""
|
||||||
if path in self._informations and key in self._informations[path]:
|
if path in self._informations and key in self._informations[path]:
|
||||||
del self._informations[path][key]
|
del self._informations[path][key]
|
||||||
elif raises:
|
elif raises:
|
||||||
raise ValueError(_(f"information's item not found \"{key}\""))
|
raise ValueError(_(f"information's item not found \"{key}\""))
|
||||||
|
|
||||||
def list_information(self,
|
def list_information(self,
|
||||||
path=None,
|
path: str=None,
|
||||||
):
|
) -> List[str]:
|
||||||
|
"""list all informations keys for a specified path
|
||||||
|
"""
|
||||||
return list(self._informations.get(path, {}).keys())
|
return list(self._informations.get(path, {}).keys())
|
||||||
|
|
||||||
#____________________________________________________________
|
#____________________________________________________________
|
||||||
# default owner methods
|
# default owner methods
|
||||||
def set_context_owner(self, owner):
|
def set_context_owner(self, owner: str) -> None:
|
||||||
":param owner: sets the default value for owner at the Config level"
|
"""set the context owner
|
||||||
|
"""
|
||||||
if owner in forbidden_owners:
|
if owner in forbidden_owners:
|
||||||
raise ValueError(_('set owner "{0}" is forbidden').format(str(owner)))
|
raise ValueError(_('set owner "{0}" is forbidden').format(str(owner)))
|
||||||
self._values[None][None][1] = owner
|
self._values[None][None][1] = owner
|
||||||
|
|
||||||
def get_context_owner(self):
|
def get_context_owner(self) -> str:
|
||||||
|
"""get the context owner
|
||||||
|
"""
|
||||||
return self._values[None][None][1]
|
return self._values[None][None][1]
|
||||||
|
|
Loading…
Reference in a new issue