diff --git a/tests/auto/test_auto.py b/tests/auto/test_auto.py
index 0744417..a492b44 100644
--- a/tests/auto/test_auto.py
+++ b/tests/auto/test_auto.py
@@ -1179,7 +1179,11 @@ def autocheck_permissive(cfg, mcfg, pathread, pathwrite, confread, confwrite, **
cfg2_ = cfg.config(confread).unrestraint
else:
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):
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']))
# 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:
# assert cfg.config(confread).unrestraint.option(pathread).permissive.get() == frozenset(['disabled'])
diff --git a/tests/test_config.py b/tests/test_config.py
index c0f6d6d..9afc3e3 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -152,6 +152,16 @@ def test_information_config():
# 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():
od1 = make_description()
cfg = Config(od1)
@@ -199,6 +209,18 @@ def test_information_option():
# 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():
od1 = make_description()
cfg = Config(od1)
@@ -390,8 +412,7 @@ def test_config_od_name(config_type):
cfg = get_config(cfg, config_type)
assert cfg.option('val.i').option.name() == 'i'
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 not list_sessions()
@@ -403,7 +424,7 @@ def test_config_od_type(config_type):
cfg = Config(o2)
cfg = get_config(cfg, config_type)
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()
diff --git a/tests/test_dyn_optiondescription.py b/tests/test_dyn_optiondescription.py
index 911390c..adefe62 100644
--- a/tests/test_dyn_optiondescription.py
+++ b/tests/test_dyn_optiondescription.py
@@ -1649,7 +1649,6 @@ def test_invalid_subdynod_dyndescription():
def test_invalid_symlink_dyndescription():
st = StrOption('st', '')
st2 = SymLinkOption('st2', st)
- st2
with pytest.raises(ConfigError):
DynOptionDescription('dod', '', [st, st2], suffixes=Calculation(return_list))
# assert not list_sessions()
@@ -1658,7 +1657,6 @@ def test_invalid_symlink_dyndescription():
def test_nocallback_dyndescription():
st = StrOption('st', '')
st2 = StrOption('st2', '')
- st, st2
with pytest.raises(TypeError):
DynOptionDescription('dod', '', [st, st2])
# assert not list_sessions()
@@ -1843,10 +1841,9 @@ def test_dyn_leadership_requires():
def test_dyn_leadership_mandatory():
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")
-# 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')
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"}))
od1 = OptionDescription(name="nsd", doc="nsd", children=[nsd_zones_all, dyn])
cfg = Config(od1)
diff --git a/tests/test_leadership.py b/tests/test_leadership.py
index 1e92db9..dc37cd1 100644
--- a/tests/test_leadership.py
+++ b/tests/test_leadership.py
@@ -6,11 +6,11 @@ import pytest
from tiramisu.setting import groups, owners
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
-groups.family = groups.GroupType('family')
+groups.addgroup('family')
def compare(calculated, expected):
@@ -94,10 +94,12 @@ def test_iter_on_groups():
#test StopIteration
break
result = cfg.option('creole').list('option',
- group_type=groups.family)
+ group_type=groups.family,
+ )
assert list(result) == []
result = cfg.option('creole.general').list('optiondescription',
- group_type=groups.family)
+ group_type=groups.family,
+ )
assert list(result) == []
# assert not list_sessions()
@@ -218,6 +220,61 @@ def test_groups_is_leader(config_type):
# 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():
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)
@@ -436,6 +493,9 @@ def test_groups_with_leader_index_mandatory(config_type):
cfg.property.read_write()
cfg = get_config(cfg, config_type)
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
with pytest.raises(ConfigError):
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()
with pytest.raises(ConfigError):
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()
with pytest.raises(ConfigError):
cfg.option('od.ip_admin_eth0', 0).option.get()
@@ -1011,17 +1071,14 @@ def test_follower_properties():
cfg = Config(od1)
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.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', 1).property.get() == ('aproperty',)
#
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', 1).property.get() == ('aproperty',)
#
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', 1).property.get() == ('aproperty', 'newproperty1')
# 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()
assert option.option.get() == ip_admin_eth0
# 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()
diff --git a/tests/test_metaconfig.py b/tests/test_metaconfig.py
index 6035c94..fb6e053 100644
--- a/tests/test_metaconfig.py
+++ b/tests/test_metaconfig.py
@@ -835,10 +835,10 @@ def test_meta_properties_requires1():
opt2 = BoolOption('opt2', "")
disabled_property = Calculation(calc_value,
Params(ParamValue('disabled'),
- kwargs={'condition': ParamOption(opt1, todict=True),
+ kwargs={'condition': ParamOption(opt1),
'expected': ParamValue(False)}))
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])
conf1 = Config(od, name='conf1')
conf1.property.read_write()
@@ -859,7 +859,7 @@ def test_meta_properties_requires_mandatory():
'expected': ParamValue('yes'),
'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_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])
conf1 = Config(od, name='conf1')
conf1.property.read_write()
diff --git a/tests/test_option.py b/tests/test_option.py
index b620b3b..b017928 100644
--- a/tests/test_option.py
+++ b/tests/test_option.py
@@ -13,13 +13,17 @@ from tiramisu.i18n import _
try:
groups.family
except:
- groups.family = groups.GroupType('family')
+ groups.addgroup('family')
def a_func():
return None
+def display_name(*args):
+ return 'display_name'
+
+
def test_option_valid_name():
IntOption('test', '')
with pytest.raises(ValueError):
@@ -76,6 +80,16 @@ def test_option_unknown():
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():
description = "it's ok"
string = 'some informations'
@@ -178,7 +192,7 @@ def test_unknown_option():
def test_optiondescription_list():
- groups.notfamily1 = groups.GroupType('notfamily1')
+ groups.addgroup('notfamily1')
i = IntOption('test', '')
i2 = IntOption('test', '')
od1 = OptionDescription('od', '', [i])
@@ -210,7 +224,7 @@ def test_optiondescription_list():
def test_optiondescription_group():
- groups.notfamily = groups.GroupType('notfamily')
+ groups.addgroup('notfamily')
i = IntOption('test', '')
i2 = IntOption('test', '')
od1 = OptionDescription('od', '', [i])
@@ -240,7 +254,7 @@ def test_optiondescription_group():
def test_optiondescription_group_redefined():
try:
- groups.notfamily = groups.GroupType('notfamily')
+ groups.addgroup('notfamily')
except:
pass
i = IntOption('test', '')
@@ -301,12 +315,6 @@ def test_intoption():
# 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():
i1 = IntOption('test1', 'description', min_number=3)
with pytest.raises(AttributeError):
@@ -322,3 +330,25 @@ def test_option_unknown_func():
cfg = Config(od)
with pytest.raises(ConfigError):
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'
diff --git a/tests/test_option_callback.py b/tests/test_option_callback.py
index 4842f66..8f326e6 100644
--- a/tests/test_option_callback.py
+++ b/tests/test_option_callback.py
@@ -145,6 +145,30 @@ def test_hidden_if_in2(config_type):
# 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):
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False)
@@ -268,7 +292,8 @@ def test_callback(config_type):
assert cfg.option('val1').value.get() == 'val'
cfg.option('val1').value.set('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()
assert cfg.option('val1').value.get() == 'val'
# assert not list_sessions()
@@ -1543,3 +1568,8 @@ def test_calc_dependencies(config_type):
assert dep[0].option.get() == val3
#
assert cfg.option('val3').option.dependencies() == []
+
+
+def test_callback__kwargs_wrong(config_type):
+ with pytest.raises(ValueError):
+ Params(kwargs='string')
diff --git a/tests/test_option_setting.py b/tests/test_option_setting.py
index 027831b..1aaf51c 100644
--- a/tests/test_option_setting.py
+++ b/tests/test_option_setting.py
@@ -60,23 +60,27 @@ def test_mod_read_only_write():
config2 = Config(od1)
assert config.property.getdefault() == {'cache', 'validator', 'warnings'}
assert config.property.getdefault('read_only', 'append') == {'frozen',
- 'disabled',
- 'validator',
- 'everything_frozen',
- 'mandatory',
- 'empty',
- 'force_store_value'}
+ 'disabled',
+ 'validator',
+ 'everything_frozen',
+ 'mandatory',
+ 'empty',
+ 'force_store_value',
+ }
assert config.property.getdefault('read_only', 'remove') == {'permissive',
- 'hidden'}
+ 'hidden',
+ }
assert config.property.getdefault('read_write', 'append') == {'frozen',
- 'disabled',
- 'validator',
- 'hidden',
- 'force_store_value'}
+ 'disabled',
+ 'validator',
+ 'hidden',
+ 'force_store_value',
+ }
assert config.property.getdefault('read_write', 'remove') == {'permissive',
- 'everything_frozen',
- 'mandatory',
- 'empty'}
+ 'everything_frozen',
+ 'mandatory',
+ 'empty',
+ }
#
config.property.setdefault(frozenset(['cache']))
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()
+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():
gcdummy = BoolOption('dummy', 'dummy', default=False, properties=('force_store_value',))
gcgroup = OptionDescription('gc', '', [gcdummy])
@@ -683,7 +699,7 @@ def test_pprint():
intoption = IntOption('int', 'Test int option', default=0)
hidden_property = Calculation(calc_value,
Params(ParamValue('hidden'),
- kwargs={'condition': ParamOption(intoption, todict=True),
+ kwargs={'condition': ParamOption(intoption),
'expected_0': ParamValue(2),
'expected_1': ParamValue(3),
'expected_2': ParamValue(4),
@@ -691,35 +707,28 @@ def test_pprint():
calc_value_property_help)
disabled_property = Calculation(calc_value,
Params(ParamValue('disabled'),
- kwargs={'condition_0': ParamOption(intoption, todict=True),
+ kwargs={'condition_0': ParamOption(intoption),
'expected_0': ParamValue(1),
- 'condition_1': ParamOption(s2, todict=True),
+ 'condition_1': ParamOption(s2),
'expected_1': ParamValue('string')}),
calc_value_property_help)
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', "")
hidden_property = Calculation(calc_value,
Params(ParamValue('hidden'),
- kwargs={'condition': ParamOption(intoption, todict=True),
+ kwargs={'condition': ParamOption(intoption),
'expected': ParamValue(1)}),
calc_value_property_help)
descr2 = OptionDescription("options", "options", [val2], properties=(hidden_property,))
- #descr2 = OptionDescription("options", "", [val2], requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}])
hidden_property = Calculation(calc_value,
Params(ParamValue('hidden'),
- kwargs={'condition': ParamOption(stroption, todict=True),
+ kwargs={'condition': ParamOption(stroption),
'expected': ParamValue('2'),
'reverse_condition': ParamValue(True)}),
calc_value_property_help)
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])
cfg = Config(od1)
@@ -775,3 +784,95 @@ def test_pprint():
assert str(err) == msg_error.format('option', 'string3', prop, '"hidden"')
del err
# 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,))
diff --git a/tests/test_option_validator.py b/tests/test_option_validator.py
index 1c83ef6..223737d 100644
--- a/tests/test_option_validator.py
+++ b/tests/test_option_validator.py
@@ -6,7 +6,8 @@ import pytest
from tiramisu import BoolOption, StrOption, IPOption, NetmaskOption, NetworkOption, BroadcastOption, \
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
from tiramisu.setting import groups
from tiramisu.error import ValueErrorWarning, ConfigError, PropertiesOptionError
@@ -105,11 +106,13 @@ def test_validator(config_type):
assert len(w) == 1
assert str(w[0].message) == msg
assert cfg.option('opt2').value.valid() is False
+ #
with warnings.catch_warnings(record=True) as w:
cfg.option('opt2').value.get()
assert len(w) == 1
assert str(w[0].message) == msg
assert cfg.option('opt2').value.valid() is False
+ #
with warnings.catch_warnings(record=True) as w:
cfg.option('opt2').value.get()
assert len(w) == 1
@@ -118,6 +121,13 @@ def test_validator(config_type):
# 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):
opt1 = StrOption('opt1', '', validators=[Calculation(return_true, Params((ParamSelfOption(), ParamValue('yes'))))], default='val')
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
if config_type != 'tiramisu-api':
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:
cfg.option('opt3').value.set(['val'])
@@ -335,7 +352,7 @@ def test_validator_warning(config_type):
assert len(w) == 1
if config_type != 'tiramisu-api':
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 pytest.raises(ValueError):
@@ -348,9 +365,9 @@ def test_validator_warning(config_type):
assert len(w) == 2
if config_type != 'tiramisu-api':
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 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()
@@ -419,13 +436,13 @@ def test_validator_warning_leadership(config_type):
assert len(w) == 1
if config_type != 'tiramisu-api':
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:
cfg.option('ip_admin_eth0.ip_admin_eth0').value.set(['val'])
if config_type != 'tiramisu-api':
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:
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'])
if config_type != 'tiramisu-api':
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:
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'])
if config_type != 'tiramisu-api':
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:
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'])
if config_type != 'tiramisu-api':
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:
assert len(w) == 3
# assert not list_sessions()
@@ -494,11 +511,12 @@ def test_validator_dependencies():
def test_validator_ip_netmask(config_type):
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])
cfg_ori = Config(od1)
cfg = cfg_ori
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('b').value.set('255.255.255.0')
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):
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])
cfg_ori = Config(od1)
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):
a = NetworkOption('a', '')
b = NetmaskOption('b', '')
- c = IPOption('c', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True), ParamOption(b, todict=True))))])
- d = IPOption('d', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True), ParamOption(b, todict=True))), warnings_only=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), ParamOption(b))), warnings_only=True)])
od1 = OptionDescription('od', '', [a, b, c, d])
warnings.simplefilter("always", ValueErrorWarning)
cfg = Config(od1)
@@ -581,8 +599,8 @@ def test_validator_ip_in_network(config_type):
def test_validator_ip_in_network_incomplete(config_type):
a = NetworkOption('a', '')
b = NetmaskOption('b', '')
- c = IPOption('c', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True), ParamOption(b, todict=True))))])
- d = IPOption('d', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True), ParamOption(b, todict=True))), warnings_only=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), ParamOption(b))), warnings_only=True)])
od1 = OptionDescription('od', '', [a, b, c, d])
warnings.simplefilter("always", ValueErrorWarning)
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):
a = NetworkOption('a', '', cidr=True)
- c = IPOption('c', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True))))])
- d = IPOption('d', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True))), warnings_only=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))), warnings_only=True)])
od1 = OptionDescription('od', '', [a, c, d])
warnings.simplefilter("always", ValueErrorWarning)
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):
a = NetworkOption('a', '', cidr=True)
- c = IPOption('c', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True))))])
- d = IPOption('d', '', validators=[Calculation(valid_in_network, Params((ParamSelfOption(), ParamOption(a, todict=True))), warnings_only=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))), warnings_only=True)])
od1 = OptionDescription('od', '', [a, c, d])
warnings.simplefilter("always", ValueErrorWarning)
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):
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])
od2 = OptionDescription('od2', '', [od])
cfg_ori = Config(od2)
@@ -886,6 +904,39 @@ def test_validator_broadcast(config_type):
# 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):
warnings.simplefilter("always", ValueErrorWarning)
a = NetworkOption('a', '', properties=('mandatory', 'disabled'))
@@ -969,7 +1020,7 @@ def test_validator_has_dependency():
def test_validator_warnings_only_more_option(config_type):
a = IntOption('a', '')
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])
cfg = Config(od1)
cfg = get_config(cfg, config_type)
@@ -988,7 +1039,7 @@ def test_validator_warnings_only_more_option(config_type):
def test_validator_error_prefix():
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])
cfg = Config(od1)
cfg.option('a').value.set(1)
@@ -1006,7 +1057,7 @@ def test_validator_error_prefix():
def test_validator_warnings_only_option(config_type):
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])
cfg_ori = Config(od1)
cfg = get_config(cfg_ori, config_type)
@@ -1086,7 +1137,7 @@ def test_validator_not_equal_leadership_default():
def test_validator_default_diff():
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])
cfg = Config(od1)
# FIXME cfg = get_config(cfg, config_type)
@@ -1107,7 +1158,7 @@ def test_validator_default_diff():
def test_validator_permissive(config_type):
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])
cfg = Config(od1)
cfg.property.read_write()
@@ -1121,7 +1172,7 @@ def test_validator_permissive(config_type):
def test_validator_disabled(config_type):
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])
cfg = Config(od1)
cfg.property.read_write()
@@ -1133,7 +1184,7 @@ def test_validator_disabled(config_type):
def test_consistency_disabled_transitive(config_type):
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])
cfg = Config(od1)
cfg.property.read_write()
@@ -1145,7 +1196,7 @@ def test_consistency_disabled_transitive(config_type):
def test_consistency_double_warnings(config_type):
a = IntOption('a', '', 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])
warnings.simplefilter("always", ValueErrorWarning)
od1 = OptionDescription('od2', '', [od])
@@ -1179,8 +1230,8 @@ def test_consistency_warnings_error(config_type):
a = IntOption('a', '', 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))))
+ Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(a))), warnings_only=True),
+ Calculation(valid_not_equal, Params((ParamSelfOption(), ParamOption(b))))
])
od1 = OptionDescription('od', '', [a, b, c])
warnings.simplefilter("always", ValueErrorWarning)
@@ -1196,7 +1247,7 @@ def test_consistency_warnings_error(config_type):
def test_consistency_not_equal_has_dependency():
a = IntOption('a', '')
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])
cfg = Config(od1)
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('b').option.has_dependency(False) is False
# 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()
diff --git a/tests/test_requires.py b/tests/test_requires.py
index 68d31df..c323570 100644
--- a/tests/test_requires.py
+++ b/tests/test_requires.py
@@ -56,7 +56,7 @@ def test_requires(config_type):
a = BoolOption('activate_service', '', True)
disabled_property = Calculation(calc_value,
Params(ParamValue('disabled'),
- kwargs={'condition': ParamOption(a, todict=True),
+ kwargs={'condition': ParamOption(a),
'expected': ParamValue(False)}))
b = IPOption('ip_address_service', '',
properties=(disabled_property,))
@@ -81,7 +81,7 @@ def test_requires_inverse(config_type):
a = BoolOption('activate_service', '', True)
disabled_property = Calculation(calc_value,
Params(ParamValue('disabled'),
- kwargs={'condition': ParamOption(a, todict=True),
+ kwargs={'condition': ParamOption(a),
'expected': ParamValue(False),
'reverse_condition': ParamValue(True)}))
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)
new_property = Calculation(calc_value,
Params(ParamValue('new'),
- kwargs={'condition': ParamOption(activate_service, todict=True),
+ kwargs={'condition': ParamOption(activate_service),
'expected': ParamValue(False)}),
calc_value_property_help)
activate_service_web = BoolOption('activate_service_web', '', True, properties=(new_property,))
disabled_property = Calculation(calc_value,
Params(ParamValue('disabled'),
- kwargs={'condition': ParamOption(activate_service_web, notraisepropertyerror=True, todict=True),
+ kwargs={'condition': ParamOption(activate_service_web, notraisepropertyerror=True),
'expected': ParamValue(False)}),
calc_value_property_help)
ip_address_service_web = IPOption('ip_address_service_web', '', properties=(disabled_property,))
diff --git a/tests/test_state.py b/tests/test_state.py
deleted file mode 100644
index 1548a8e..0000000
--- a/tests/test_state.py
+++ /dev/null
@@ -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)
diff --git a/tests/test_submulti.py b/tests/test_submulti.py
index a7235aa..967554e 100644
--- a/tests/test_submulti.py
+++ b/tests/test_submulti.py
@@ -8,7 +8,7 @@ import warnings
from tiramisu.setting import groups, owners
from tiramisu import StrOption, IntOption, OptionDescription, submulti, Leadership, Config, \
MetaConfig, undefined, Params, ParamOption, Calculation
-from tiramisu.error import LeadershipError
+from tiramisu.error import LeadershipError, PropertiesOptionError
def return_val(val=None):
@@ -48,6 +48,51 @@ def test_submulti():
# 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():
with pytest.raises(ValueError):
StrOption('multi2', '', default_multi='yes', multi=submulti)
@@ -235,6 +280,50 @@ def test_values_with_leader_and_followers_submulti():
# 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():
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'])
diff --git a/tests/test_symlink.py b/tests/test_symlink.py
index 0499346..5937ece 100644
--- a/tests/test_symlink.py
+++ b/tests/test_symlink.py
@@ -4,10 +4,11 @@ from .autopath import do_autopath
do_autopath()
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
from tiramisu.error import PropertiesOptionError, ConfigError
from tiramisu.setting import groups, owners
+from tiramisu.i18n import _
def return_value():
@@ -19,9 +20,14 @@ def test_symlink_option(config_type):
boolopt = BoolOption("b", "", default=False)
linkopt = SymLinkOption("c", boolopt)
od1 = OptionDescription("opt", "",
- [linkopt, OptionDescription("s1", "", [boolopt])])
+ [linkopt, OptionDescription("s1", "", [boolopt])],
+ )
cfg = Config(od1)
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
cfg.option("s1.b").value.set(True)
cfg.option("s1.b").value.set(False)
@@ -36,6 +42,62 @@ def test_symlink_option(config_type):
# 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):
boolopt = BoolOption("b", "", default=False)
linkopt = SymLinkOption("c", boolopt)
@@ -66,14 +128,10 @@ def test_symlink_addproperties():
od1 = OptionDescription('opt', '', [boolopt, linkopt])
cfg = Config(od1)
cfg.property.read_write()
- with pytest.raises(TypeError):
+ with pytest.raises(ConfigError):
cfg.option('c').property.add('new')
- try:
+ with pytest.raises(ConfigError):
cfg.option('c').property.reset()
- except AssertionError:
- pass
- else:
- raise Exception('must raise')
# assert not list_sessions()
@@ -94,14 +152,10 @@ def test_symlink_addpermissives():
od1 = OptionDescription('opt', '', [boolopt, linkopt])
cfg = Config(od1)
cfg.property.read_write()
- with pytest.raises(TypeError):
+ with pytest.raises(ConfigError):
cfg.option('c').permissive.set(frozenset(['new']))
- try:
+ with pytest.raises(ConfigError):
cfg.option('c').permissive.reset()
- except AssertionError:
- pass
- else:
- raise Exception('must raise')
# assert not list_sessions()
@@ -340,3 +394,14 @@ def test_symlink_list(config_type):
list_opt.append(opt.option.path())
assert list_opt == ['c', 's1.b']
# 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()
diff --git a/tiramisu/api.py b/tiramisu/api.py
index 3078d69..730692c 100644
--- a/tiramisu/api.py
+++ b/tiramisu/api.py
@@ -14,20 +14,19 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
# ____________________________________________________________
-from inspect import ismethod, getdoc, signature
-from time import time
-from typing import List, Set, Any, Optional, Callable, Union, Dict
+from inspect import getdoc
+from typing import List, Set, Any, Optional, Callable, Dict
from warnings import catch_warnings, simplefilter
from functools import wraps
from copy import deepcopy
-from .error import ConfigError, LeadershipError, PropertiesOptionError, ValueErrorWarning
+from .error import ConfigError, LeadershipError, ValueErrorWarning
from .i18n import _
-from .setting import ConfigBag, OptionBag, owners, groups, Undefined, undefined, \
- FORBIDDEN_SET_PROPERTIES, SPECIAL_PROPERTIES, EXPIRATION_TIME
+from .setting import ConfigBag, OptionBag, owners, groups, undefined, \
+ FORBIDDEN_SET_PROPERTIES, SPECIAL_PROPERTIES
from .config import KernelConfig, KernelGroupConfig, KernelMetaConfig, KernelMixConfig
-from .option import RegexpOption, OptionDescription
+from .option import RegexpOption, OptionDescription, ChoiceOption
from .todict import TiramisuDict
@@ -42,13 +41,12 @@ class TiramisuHelp:
def display(doc=''):
if _display: # pragma: no cover
print(doc)
- options = []
all_modules = dir(self)
modules = []
max_len = 0
force = False
for module_name in all_modules:
- if module_name in ['forcepermissive', 'unrestraint']:
+ if module_name in ['forcepermissive', 'unrestraint', 'nowarnings']:
force = True
max_len = max(max_len, len('forcepermissive'))
elif module_name != 'help' and not module_name.startswith('_'):
@@ -60,8 +58,16 @@ class TiramisuHelp:
display()
if force:
display(_('Settings:'))
- display(self._tmpl_help.format('forcepermissive', _('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('forcepermissive',
+ _('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()
if isinstance(self, TiramisuDispatcherOption):
doc = _(getdoc(self.__call__))
@@ -81,7 +87,6 @@ class TiramisuHelp:
class CommonTiramisu(TiramisuHelp):
- _allow_optiondescription = True
_validate_properties = True
def _get_options_bag(self) -> OptionBag:
@@ -98,14 +103,6 @@ class CommonTiramisu(TiramisuHelp):
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):
if not isinstance(typ, list):
types = [typ]
@@ -115,16 +112,17 @@ def option_type(typ):
def wrapper(func):
@wraps(func)
def wrapped(*args, **kwargs):
- config_bag = args[0]._config_bag
- if args[0]._config_bag.context.impl_type == 'group' and 'group' in types:
+ self = args[0]
+ config_bag = self._config_bag
+ if self._config_bag.context.impl_type == 'group' and 'group' in types:
options_bag = [OptionBag(None,
None,
- args[0]._config_bag,
- path=args[0]._path,
+ self._config_bag,
+ path=self._path,
)]
kwargs['is_group'] = True
- return func(args[0], options_bag, *args[1:], **kwargs)
- options_bag = args[0]._get_options_bag()
+ return func(self, options_bag, *args[1:], **kwargs)
+ options_bag = self._get_options_bag()
option = options_bag[-1].option
if option.impl_is_optiondescription() and 'optiondescription' in types or \
not option.impl_is_optiondescription() and (
@@ -133,24 +131,29 @@ def option_type(typ):
'option' in types or \
option.impl_is_leader() and 'leader' in types or \
option.impl_is_follower() and 'follower' in types or \
- option.get_type() == 'choice' and 'choice' in types)):
- if not option.impl_is_optiondescription() and not option.impl_is_symlinkoption() and option.impl_is_follower():
- if 'with_index' in types and args[0]._index is not None:
- raise ConfigError(_(f'please do not specify index ({args[0].__class__.__name__}.{func.__name__})'))
- if 'with_index' not in types and args[0]._index is None:
- raise ConfigError(_(f'please specify index with a follower option ({args[0].__class__.__name__}.{func.__name__})'))
- elif args[0]._index is not None:
- raise ConfigError(_(f'please specify an index only for follower option ({args[0].__class__.__name__}.{func.__name__})'))
- return func(args[0], options_bag, *args[1:], **kwargs)
- raise ConfigError(_(f'please specify a valid sub function ({args[0].__class__.__name__}.{func.__name__})'))
+ 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 'with_index' not in types and 'with_or_without_index' not in types and \
+ self._index is not None:
+ msg = _('please do not specify index '
+ f'({self.__class__.__name__}.{func.__name__})')
+ raise ConfigError(_(msg))
+ 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
return wrapped
return wrapper
class CommonTiramisuOption(CommonTiramisu):
- _allow_optiondescription = False
- _follower_need_index = True
_validate_properties = False
def __init__(self,
@@ -167,60 +170,14 @@ class CommonTiramisuOption(CommonTiramisu):
class _TiramisuOptionWalk:
- def _filter(self,
- opt,
- subconfig,
- config_bag,
- ):
- option_bag = OptionBag(opt,
- None,
- config_bag,
- )
-
- def _walk(self,
- option,
- recursive,
- type_,
+ def _list(self,
+ root_option_bag,
+ type,
group_type,
- config_bag,
- subconfig,
+ recursive,
):
- options = []
- for opt in option.get_children(config_bag):
- 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 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)
options = []
@@ -233,11 +190,18 @@ class _TiramisuOptionWalk:
group_type=group_type,
):
if isinstance(option_bag, dict):
- for opt_bag in option_bag.values():
- options.append(TiramisuOption(opt_bag.path,
- opt_bag.index,
- self._config_bag,
- ))
+ for opts_bag in option_bag.values():
+ if isinstance(opts_bag, OptionBag):
+ options.append(TiramisuOption(opts_bag.path,
+ 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:
options.append(TiramisuOption(option_bag.path,
option_bag.index,
@@ -245,82 +209,48 @@ class _TiramisuOptionWalk:
))
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):
"""Manage option"""
- _allow_optiondescription = True
- _follower_need_index = False
_validate_properties = False
- @load_option
+ @option_type(['optiondescription', 'option', 'with_or_without_index'])
def get(self, options_bag: List[OptionBag]):
"""Get Tiramisu option"""
option_bag = options_bag[-1]
return option_bag.option
- @load_option
+ @option_type(['optiondescription'])
def isleadership(self, options_bag: List[OptionBag]):
"""Test if option is a leader or a follower"""
option_bag = options_bag[-1]
return option_bag.option.impl_is_leadership()
- @load_option
+ @option_type(['optiondescription', 'option', 'with_or_without_index'])
def doc(self, options_bag: List[OptionBag]):
"""Get option document"""
option_bag = options_bag[-1]
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]):
"""Get option description"""
option_bag = options_bag[-1]
return option_bag.option.impl_get_information('doc', None)
- @load_option
- def name(self,
- options_bag: List[OptionBag],
- follow_symlink: bool=False,
- ) -> str:
+ @option_type(['optiondescription', 'option', 'symlink', 'with_or_without_index'])
+ def name(self, options_bag: List[OptionBag]) -> str:
"""Get option name"""
option_bag = options_bag[-1]
- if not follow_symlink or \
- 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()
+ return option_bag.option.impl_getname()
- @load_option
+ @option_type(['optiondescription', 'option', 'with_or_without_index', 'symlink'])
def path(self, options_bag: List[OptionBag]) -> str:
"""Get option path"""
option_bag = options_bag[-1]
return option_bag.path
- @load_option
+ @option_type(['optiondescription', 'option', 'symlink'])
def has_dependency(self,
options_bag: List[OptionBag],
self_is_dep=True,
@@ -329,7 +259,7 @@ class _TiramisuOptionOptionDescription(CommonTiramisuOption):
option_bag = options_bag[-1]
return option_bag.option.impl_has_dependency(self_is_dep)
- @load_option
+ @option_type(['optiondescription', 'option'])
def dependencies(self, options_bag: List[OptionBag]):
"""Get dependencies from this option"""
option_bag = options_bag[-1]
@@ -341,13 +271,13 @@ class _TiramisuOptionOptionDescription(CommonTiramisuOption):
))
return options
- @load_option
+ @option_type(['optiondescription', 'option', 'with_or_without_index'])
def isoptiondescription(self, options_bag: List[OptionBag]):
"""Test if option is an optiondescription"""
option_bag = options_bag[-1]
return option_bag.option.impl_is_optiondescription()
- @load_option
+ @option_type(['optiondescription', 'option', 'with_index'])
def properties(self,
options_bag: List[OptionBag],
only_raises=False,
@@ -364,7 +294,6 @@ class _TiramisuOptionOptionDescription(CommonTiramisuOption):
return settings.getproperties(option_bag,
apply_requires=False,
)
- # do not check cache properties/permissives which are not save (unrestraint, ...)
return settings.calc_raises_properties(option_bag,
apply_requires=False,
uncalculated=uncalculated,
@@ -383,55 +312,51 @@ class _TiramisuOptionOptionDescription(CommonTiramisuOption):
class TiramisuOptionOption(_TiramisuOptionOptionDescription):
"""Manage option"""
- @load_option
+ @option_type(['option', 'symlink', 'with_or_without_index'])
def ismulti(self, options_bag: List[OptionBag]):
"""Test if option could have multi value"""
option_bag = options_bag[-1]
return option_bag.option.impl_is_multi()
- @load_option
+ @option_type(['option', 'symlink', 'with_or_without_index'])
def issubmulti(self, options_bag: List[OptionBag]):
"""Test if option could have submulti value"""
option_bag = options_bag[-1]
return option_bag.option.impl_is_submulti()
- @load_option
+ @option_type(['option', 'with_or_without_index'])
def isleader(self, options_bag: List[OptionBag]):
"""Test if option is a leader"""
- option_bag = options_bag[-1]
- return option_bag.option.impl_is_leader()
+ return options_bag[-1].option.impl_is_leader()
- @load_option
+ @option_type(['option', 'with_or_without_index'])
def isfollower(self, options_bag: List[OptionBag]):
"""Test if option is a follower"""
- option_bag = options_bag[-1]
- return option_bag.option.impl_is_follower()
+ return options_bag[-1].option.impl_is_follower()
- @load_option
+ @option_type(['option', 'optiondescription', 'with_or_without_index'])
def isdynamic(self, options_bag: List[OptionBag]):
"""Test if option is a dynamic optiondescription"""
- option_bag = options_bag[-1]
- return option_bag.option.impl_is_dynsymlinkoption()
+ return options_bag[-1].option.impl_is_dynsymlinkoption()
- @load_option
+ @option_type(['option', 'symlink', 'with_or_without_index'])
def issymlinkoption(self, options_bag: List[OptionBag]) -> bool:
"""Test if option is a symlink option"""
- option_bag = options_bag[-1]
- return option_bag.option.impl_is_symlinkoption()
+ return options_bag[-1].option.impl_is_symlinkoption()
- @load_option
+ @option_type(['option', 'with_or_without_index', 'symlink'])
def default(self, options_bag: List[OptionBag]):
"""Get default value for an option (not for optiondescription)"""
- option_bag = options_bag[-1]
- return option_bag.option.impl_getdefault()
+ return options_bag[-1].option.impl_getdefault()
- @load_option
+ @option_type(['option', 'with_or_without_index', 'symlink'])
def defaultmulti(self, options_bag: List[OptionBag]):
"""Get default value when added a value for a multi option (not for optiondescription)"""
- option_bag = options_bag[-1]
- return option_bag.option.impl_getdefault_multi()
+ if not options_bag[-1].option.impl_is_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]):
"""Get de option type"""
option_bag = options_bag[-1]
@@ -439,7 +364,7 @@ class TiramisuOptionOption(_TiramisuOptionOptionDescription):
return 'optiondescription'
return option_bag.option.get_type()
- @load_option
+ @option_type('option')
def pattern(self, options_bag: List[OptionBag]) -> str:
"""Get the option pattern"""
option_bag = options_bag[-1]
@@ -456,15 +381,16 @@ class TiramisuOptionOption(_TiramisuOptionOptionDescription):
#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]?)$'
- @load_option
+ @option_type('option')
def leader(self, options_bag: List[OptionBag]):
"""Get the leader option for a follower option"""
- option_bag = options_bag[-1]
- return TiramisuOption(option_bag.option.impl_get_leadership().get_leader().impl_getpath(),
+ path = options_bag[-1].option.impl_get_leadership().get_leader().impl_getpath()
+ return TiramisuOption(path,
None,
- self._config_bag)
+ self._config_bag,
+ )
- @load_option
+ @option_type(['option', 'with_or_without_index'])
def index(self, options_bag: List[OptionBag]):
"""Get then index of option"""
return options_bag[-1].index
@@ -474,7 +400,7 @@ class TiramisuOptionOwner(CommonTiramisuOption):
#FIXME optiondescription must not have Owner!
"""Manage option's owner"""
- @option_type(['symlink', 'option'])
+ @option_type(['symlink', 'option', 'with_index'])
def get(self, options_bag: List[OptionBag]):
"""Get owner for a specified option"""
option_bag = options_bag[-1]
@@ -482,17 +408,15 @@ class TiramisuOptionOwner(CommonTiramisuOption):
parent_option_bag = options_bag[-2]
else:
parent_option_bag = None
- return self._config_bag.context.get_owner(option_bag,
- parent_option_bag,
- )
+ return self._config_bag.context.get_owner(option_bag)
- @option_type(['symlink', 'option'])
+ @option_type(['symlink', 'option', 'with_index'])
def isdefault(self, options_bag: List[OptionBag]):
"""Is option has defaut value"""
option_bag = options_bag[-1]
return self._config_bag.context.get_values().is_default_owner(option_bag)
- @option_type('option')
+ @option_type(['option', 'with_index'])
def set(self,
options_bag: List[OptionBag],
owner: str,
@@ -511,11 +435,9 @@ class TiramisuOptionOwner(CommonTiramisuOption):
class TiramisuOptionProperty(CommonTiramisuOption):
"""Manage option's property"""
- _allow_optiondescription = True
- _follower_need_index = False
_validate_properties = False
- @load_option
+ @option_type(['option', 'optiondescription', 'with_index'])
def get(self,
options_bag: List[OptionBag],
only_raises=False,
@@ -525,14 +447,13 @@ class TiramisuOptionProperty(CommonTiramisuOption):
option_bag = options_bag[-1]
if not only_raises:
return option_bag.properties
- # do not check cache properties/permissives which are not save (unrestraint, ...)
settings = self._config_bag.context.get_settings()
ret = settings.calc_raises_properties(option_bag,
uncalculated=uncalculated,
)
return ret
- @load_option
+ @option_type(['option', 'optiondescription', 'with_or_without_index'])
def add(self,
options_bag: List[OptionBag],
prop,):
@@ -542,15 +463,15 @@ class TiramisuOptionProperty(CommonTiramisuOption):
raise ConfigError(_('cannot add this property: "{0}"').format(
' '.join(prop)))
settings = self._config_bag.context.get_settings()
- props = settings._getproperties(option_bag.path,
- option_bag.index,
- option_bag.option.impl_getproperties(),
- )
+ props = settings.get_stored_properties(option_bag.path,
+ option_bag.index,
+ option_bag.option.impl_getproperties(),
+ )
settings.setproperties(option_bag,
props | {prop},
)
- @load_option
+ @option_type(['option', 'optiondescription', 'with_or_without_index'])
def remove(self,
options_bag: List[OptionBag],
prop,
@@ -562,7 +483,7 @@ class TiramisuOptionProperty(CommonTiramisuOption):
props - {prop},
)
- @load_option
+ @option_type(['option', 'optiondescription', 'with_or_without_index'])
def reset(self, options_bag: List[OptionBag]):
"""Reset all personalised properties"""
option_bag = options_bag[-1]
@@ -571,16 +492,14 @@ class TiramisuOptionProperty(CommonTiramisuOption):
class TiramisuOptionPermissive(CommonTiramisuOption):
"""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]):
"""Get permissives value"""
option_bag = options_bag[-1]
return self._config_bag.context.get_settings().getpermissives(option_bag)
- @load_option
+ @option_type(['option', 'optiondescription', 'with_or_without_index'])
def set(self,
options_bag: List[OptionBag],
permissives,
@@ -591,7 +510,7 @@ class TiramisuOptionPermissive(CommonTiramisuOption):
permissives=permissives,
)
- @load_option
+ @option_type(['option', 'optiondescription', 'with_index'])
def reset(self, options_bag: List[OptionBag]):
"""Reset all personalised permissive"""
option_bag = options_bag[-1]
@@ -600,40 +519,36 @@ class TiramisuOptionPermissive(CommonTiramisuOption):
class TiramisuOptionInformation(CommonTiramisuOption):
"""Manage option's informations"""
- _allow_optiondescription = True
- _follower_need_index = False
- @load_option
+ @option_type(['option', 'optiondescription', 'with_or_without_index'])
def get(self,
options_bag: List[OptionBag],
- key: str,
+ name: str,
default=undefined,
) -> Any:
"""Get information"""
option_bag = options_bag[-1]
try:
- return self._config_bag.context.get_values().get_information(self._config_bag,
- option_bag,
- key,
+ return self._config_bag.context.get_values().get_information(option_bag,
+ name,
undefined,
)
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,
options_bag: List[OptionBag],
key: str,
value: Any) -> None:
"""Set information"""
option_bag = options_bag[-1]
- self._config_bag.context.get_values().set_information(self._config_bag,
- option_bag,
+ self._config_bag.context.get_values().set_information(option_bag,
key,
value,
)
- @load_option
+ @option_type(['option', 'optiondescription'])
def reset(self,
options_bag: List[OptionBag],
key: str,
@@ -644,7 +559,7 @@ class TiramisuOptionInformation(CommonTiramisuOption):
path=option_bag.path,
)
- @load_option
+ @option_type(['option', 'optiondescription', 'with_or_without_index'])
def list(self,
options_bag: List[OptionBag],
) -> list:
@@ -657,19 +572,14 @@ class TiramisuOptionInformation(CommonTiramisuOption):
class TiramisuOptionValue(CommonTiramisuOption):
"""Manage option's value"""
- _allow_optiondescription = True
- _follower_need_index = True
_validate_properties = True
@option_type('optiondescription')
def dict(self, options_bag: List[OptionBag]):
"""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])
- @option_type(['option', 'symlink'])
+ @option_type(['option', 'symlink', 'with_index'])
def get(self,
options_bag: List[OptionBag],
):
@@ -688,7 +598,7 @@ class TiramisuOptionValue(CommonTiramisuOption):
parent_option_bag,
)
- @option_type('option')
+ @option_type(['option', 'with_index'])
def set(self,
options_bag: List[OptionBag],
value,
@@ -701,17 +611,18 @@ class TiramisuOptionValue(CommonTiramisuOption):
idx = value.index(undefined)
soption_bag = option_bag.copy()
soption_bag.index = idx
- value[idx] = values.getdefaultvalue(soption_bag)
+ value[idx] = values.get_default_value(soption_bag)
elif value == undefined:
- value = values.getdefaultvalue(option_bag)
- if option_bag.option.impl_is_leader() and len(value) < self._config_bag.context.get_length_leadership(options_bag[-2]):
+ 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]):
raise LeadershipError(_('cannot reduce length of the leader "{}"'
'').format(option_bag.option.impl_get_display_name()))
return option_bag.config_bag.context.set_value(option_bag,
value,
)
- @option_type(['group', 'option'])
+ @option_type(['group', 'option', 'with_index'])
def reset(self,
options_bag: List[OptionBag],
is_group: bool=False,
@@ -723,26 +634,18 @@ class TiramisuOptionValue(CommonTiramisuOption):
self._config_bag,
)
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]):
"""Get default value (default of option or calculated value)"""
- option_bag = 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)
+ return self._config_bag.context.get_values().get_default_value(options_bag[-1])
- @option_type('option')
+ @option_type(['option', 'with_index'])
def valid(self, options_bag: List[OptionBag]):
"""The if the option's value is valid"""
option_bag = options_bag[-1]
@@ -757,7 +660,7 @@ class TiramisuOptionValue(CommonTiramisuOption):
return False
return True
- @option_type('choice')
+ @option_type(['choice', 'with_index'])
def list(self, options_bag: List[OptionBag]):
"""All values available for a ChoiceOption"""
option_bag = options_bag[-1]
@@ -766,19 +669,15 @@ class TiramisuOptionValue(CommonTiramisuOption):
@option_type('leader')
def pop(self,
options_bag: List[OptionBag],
- index: int):
+ index: int,
+ ):
"""Pop a value"""
- option_bag = options_bag[-1]
- if len(options_bag) > 1:
- leadership_option_bag = options_bag[-2]
- else:
- leadership_option_bag = None
- self._config_bag.context.pop_leader(option_bag,
- leadership_option_bag,
- index,
- )
+ self._config_bag.context.get_values().reset_leadership(options_bag[-1],
+ options_bag[-2],
+ index,
+ )
- @option_type(['leader', 'follower', 'with_index'])
+ @option_type(['leader', 'follower', 'with_or_without_index'])
def len(self, options_bag: List[OptionBag]):
"""Length for a follower option"""
return self._config_bag.context.get_length_leadership(options_bag[-2])
@@ -786,7 +685,7 @@ class TiramisuOptionValue(CommonTiramisuOption):
def _registers(_registers: Dict[str, type],
prefix: str,
- extra_type: Optional[type]=None):
+ ):
for module_name in globals().keys():
if module_name != prefix and module_name.startswith(prefix):
module = globals()[module_name]
@@ -825,7 +724,7 @@ class TiramisuConfig(TiramisuHelp, _TiramisuOptionWalk):
for config_bag in self._orig_config_bags:
config_bag.properties = properties
config_bag.permissives = permissives
-
+
def name(self):
"""get the name"""
return self._config_bag.context.impl_getname()
@@ -893,11 +792,11 @@ class TiramisuOption(CommonTiramisu, TiramisuConfig):
group_type=None,
):
"""List options (by default list only option)"""
- return self._list2(options_bag[-1],
- type,
- group_type,
- recursive,
- )
+ return self._list(options_bag[-1],
+ type,
+ group_type,
+ recursive,
+ )
def _load_dict(self,
clearable: str="all",
@@ -943,8 +842,7 @@ class TiramisuContextInformation(TiramisuConfig):
"""Get an information"""
values = self._config_bag.context.get_values()
try:
- return values.get_information(self._config_bag,
- None,
+ return values.get_information(None,
name,
undefined,
)
@@ -1115,7 +1013,6 @@ class TiramisuContextProperty(TiramisuConfig):
def add(self, prop):
"""Add a config property"""
- settings = self._config_bag.context.get_settings()
props = set(self.get())
if prop not in props:
props.add(prop)
@@ -1128,12 +1025,8 @@ class TiramisuContextProperty(TiramisuConfig):
props.remove(prop)
self._set(frozenset(props))
- def get(self,
- default=False):
+ def get(self):
"""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
def _set(self,
@@ -1168,7 +1061,6 @@ class TiramisuContextProperty(TiramisuConfig):
force_store_value = 'force_store_value' not in self._config_bag.properties
else:
force_store_value = False
- settings = self._config_bag.context.get_settings()
self._config_bag.context.get_settings()._properties = deepcopy(properties)
self._config_bag.context.reset_cache(None, None)
self._reset_config_properties()
@@ -1205,8 +1097,9 @@ class TiramisuContextProperty(TiramisuConfig):
raise ValueError(_('unknown type {}').format(type))
def getdefault(self,
- type: Optional[str]=None,
- when: Optional[str]=None) -> Set[str]:
+ type: Optional[str]=None,
+ when: Optional[str]=None,
+ ) -> Set[str]:
setting = self._config_bag.context.get_settings()
if type is None and when is None:
return setting.default_properties
@@ -1216,15 +1109,12 @@ class TiramisuContextProperty(TiramisuConfig):
if type == 'read_only':
if when == 'append':
return setting.ro_append
- else:
- return setting.ro_remove
- elif type == 'read_write':
+ return setting.ro_remove
+ if type == 'read_write':
if when == 'append':
return setting.rw_append
- else:
- return setting.rw_remove
- else:
- raise ValueError(_('unknown type {}').format(type))
+ return setting.rw_remove
+ raise ValueError(_('unknown type {}').format(type))
class TiramisuContextPermissive(TiramisuConfig):
@@ -1302,7 +1192,8 @@ class TiramisuContextOption(TiramisuConfig, _TiramisuOptionWalk):
):
option = TiramisuOption(path,
None,
- self._config_bag)
+ self._config_bag,
+ )
if first:
return option
options.append(option)
@@ -1318,11 +1209,11 @@ class TiramisuContextOption(TiramisuConfig, _TiramisuOptionWalk):
None,
self._config_bag,
)
- return self._list2(root_option_bag,
- type,
- group_type,
- recursive,
- )
+ return self._list(root_option_bag,
+ type,
+ group_type,
+ recursive,
+ )
def _load_dict(self,
clearable="all",
@@ -1336,10 +1227,12 @@ class TiramisuContextOption(TiramisuConfig, _TiramisuOptionWalk):
def dict(self,
clearable="all",
remotable="minimum",
- form=[],
+ form=None,
force=False,
):
"""Convert config and option to tiramisu format"""
+ if form is None:
+ form = []
if force or self._tiramisu_dict is None:
self._load_dict(clearable, remotable)
return self._tiramisu_dict.todict(form)
@@ -1356,7 +1249,6 @@ class _TiramisuContextConfigReset():
def reset(self):
"""Remove all datas to current config (informations, values, properties, ...)"""
# Option's values
- settings = self._config_bag.context.get_settings()
context_owner = self._config_bag.context.get_values().get_context_owner()
self._config_bag.context.get_values()._values = {None: {None: [None, context_owner]}}
# Option's informations
@@ -1470,6 +1362,7 @@ class _TiramisuContextMixConfig(_TiramisuContextGroupConfig, _TiramisuContextCon
def add(self,
config):
"""Add config from MetaConfig"""
+ # pylint: disable=protected-access
self._config_bag.context.add_config(config._config_bag.context)
def parents(self):
@@ -1495,7 +1388,8 @@ class TiramisuContextCache(TiramisuConfig):
self._config_bag.context.reset_cache(None, None)
def set_expiration_time(self,
- time: int) -> None:
+ time: int,
+ ) -> None:
"""Change expiration time value"""
self._config_bag.expiration_time = time
@@ -1505,6 +1399,8 @@ class TiramisuContextCache(TiramisuConfig):
class TiramisuAPI(TiramisuHelp):
+ """TiramisuAPI common class
+ """
_registers = {}
def __init__(self,
@@ -1520,16 +1416,19 @@ class TiramisuAPI(TiramisuHelp):
config_bag = self._config_bag
return TiramisuDispatcherOption(config_bag,
self._orig_config_bags)
- elif subfunc in ['forcepermissive', 'unrestraint']:
+ if subfunc in ['forcepermissive', 'unrestraint', 'nowarnings']:
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()
if subfunc == 'unrestraint':
config_bag.unrestraint()
+ elif subfunc == 'nowarnings':
+ config_bag.nowarnings()
else:
config_bag.set_permissive()
return TiramisuAPI(config_bag, [self._config_bag])
- elif subfunc == 'config':
+ if subfunc == 'config':
config_type = self._config_bag.context.impl_type
if config_type == 'group':
config = _TiramisuContextGroupConfig
@@ -1541,7 +1440,7 @@ class TiramisuAPI(TiramisuHelp):
config = _TiramisuContextConfig
return config(self._config_bag,
self._orig_config_bags)
- elif subfunc in self._registers:
+ if subfunc in self._registers:
config_bag = self._config_bag
# del config_bag.permissives
return self._registers[subfunc](config_bag,
@@ -1549,18 +1448,21 @@ class TiramisuAPI(TiramisuHelp):
raise ConfigError(_('please specify a valid sub function ({})').format(subfunc))
def __dir__(self):
- return list(self._registers.keys()) + ['unrestraint', 'forcepermissive', 'config']
+ return list(self._registers.keys()) + \
+ ['unrestraint', 'forcepermissive', 'nowarnings', 'config']
class TiramisuDispatcherOption(TiramisuContextOption):
"""Select an option"""
def __call__(self,
path: str,
- index: Optional[int]=None) -> TiramisuOption:
+ index: Optional[int]=None,
+ ) -> TiramisuOption:
"""Select an option by path"""
return TiramisuOption(path,
index,
- self._config_bag)
+ self._config_bag,
+ )
class Config(TiramisuAPI):
@@ -1591,18 +1493,23 @@ class Config(TiramisuAPI):
del self._config_bag.context
del self._config_bag
del self._orig_config_bags
- except:
+ except ConfigError:
pass
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,
- children: 'Config'=[],
+ children: 'Config'=None,
name=None,
optiondescription: Optional[OptionDescription]=None,
display_name=None
) -> None:
+ if children is None:
+ children = []
if isinstance(children, KernelMetaConfig):
config = children
else:
@@ -1628,7 +1535,10 @@ class MetaConfig(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,
optiondescription: OptionDescription,
children: List[Config],
@@ -1661,6 +1571,7 @@ class MixConfig(TiramisuAPI):
class GroupConfig(TiramisuAPI):
"""GroupConfig that enables us to access the sub configuration's options"""
+ # pylint: disable=too-few-public-methods
def __init__(self,
children,
name=None,
diff --git a/tiramisu/autolib.py b/tiramisu/autolib.py
index 8d6af7d..3ac882b 100644
--- a/tiramisu/autolib.py
+++ b/tiramisu/autolib.py
@@ -24,6 +24,7 @@ from itertools import chain
from .error import PropertiesOptionError, ConfigError, LeadershipError, ValueWarning
from .i18n import _
from .setting import undefined, ConfigBag, OptionBag, Undefined
+from .function import FUNCTION_WAITING_FOR_DICT
# ____________________________________________________________
@@ -58,15 +59,15 @@ class Param:
class ParamOption(Param):
- __slots__ = ('todict',
- 'option',
+ __slots__ = ('option',
'notraisepropertyerror',
- 'raisepropertyerror')
+ 'raisepropertyerror',
+ )
def __init__(self,
option: 'Option',
notraisepropertyerror: bool=False,
raisepropertyerror: bool=False,
- todict: bool=False) -> None:
+ ) -> None:
if __debug__ and not hasattr(option, 'impl_is_symlinkoption'):
raise ValueError(_('paramoption needs an option not {}').format(type(option)))
if option.impl_is_symlinkoption():
@@ -75,7 +76,6 @@ class ParamOption(Param):
cur_opt = option
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))
- self.todict = todict
self.option = cur_opt
self.notraisepropertyerror = notraisepropertyerror
self.raisepropertyerror = raisepropertyerror
@@ -90,12 +90,10 @@ class ParamDynOption(ParamOption):
notraisepropertyerror: bool=False,
raisepropertyerror: bool=False,
optional: bool=False,
- todict: bool=False,
) -> None:
super().__init__(option,
notraisepropertyerror,
raisepropertyerror,
- todict,
)
self.suffix = suffix
self.dynoptiondescription = dynoptiondescription
@@ -103,12 +101,11 @@ class ParamDynOption(ParamOption):
class ParamSelfOption(Param):
- __slots__ = ('todict', 'whole')
+ __slots__ = ('whole')
def __init__(self,
- todict: bool=False,
- whole: bool=undefined) -> None:
+ whole: bool=undefined,
+ ) -> None:
"""whole: send all value for a multi, not only indexed value"""
- self.todict = todict
if whole is not undefined:
self.whole = whole
@@ -206,23 +203,13 @@ class Calculation:
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):
pass
-def manager_callback(callbk: Param,
+def manager_callback(callback: Callable,
+ param: Param,
option,
index: Optional[int],
orig_value,
@@ -231,10 +218,10 @@ def manager_callback(callbk: Param,
for_settings: bool,
) -> Any:
"""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 hasattr(callbk, 'whole'):
- whole = callbk.whole
+ if hasattr(param, 'whole'):
+ whole = param.whole
else:
# if value is same_leadership, follower are isolate by default
# otherwise option is a whole option
@@ -243,7 +230,7 @@ def manager_callback(callbk: Param,
return index
return None
- def calc_self(callbk,
+ def calc_self(param,
option,
index,
value,
@@ -251,10 +238,8 @@ def manager_callback(callbk: Param,
):
# index must be apply only if 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 config_bag is undefined:
- return undefined
path = option.impl_getpath()
option_bag = OptionBag(option,
None,
@@ -266,7 +251,7 @@ def manager_callback(callbk: Param,
)
parent_option_bag, option_bag = get_option_bag(config_bag,
option,
- callbk,
+ param,
apply_index,
True,
properties=properties,
@@ -276,17 +261,17 @@ def manager_callback(callbk: Param,
for idx in range(config_bag.context.get_length_leadership(parent_option_bag)):
parent_option_bag, option_bag = get_option_bag(config_bag,
option,
- callbk,
+ param,
idx,
True,
properties=properties,
)
- new_value.append(get_value(callbk,
+ new_value.append(get_value(param,
option_bag,
path,
))
else:
- new_value = get_value(callbk,
+ new_value = get_value(param,
option_bag,
path,
)
@@ -297,7 +282,7 @@ def manager_callback(callbk: Param,
value = value[apply_index]
return value
- def get_value(callbk,
+ def get_value(param,
option_bag,
path,
):
@@ -306,14 +291,14 @@ def manager_callback(callbk: Param,
value = config_bag.context.get_value(option_bag)
except PropertiesOptionError as err:
# 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 ConfigError(_('unable to carry out a calculation for "{}"'
', {}').format(option.impl_get_display_name(), err), err) from 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
except AttributeError as err:
- if isinstance(callbk, ParamDynOption) and callbk.optional:
+ if isinstance(param, ParamDynOption) and param.optional:
# cannot acces, simulate a propertyerror
raise PropertiesOptionError(option_bag,
['configerror'],
@@ -324,7 +309,7 @@ def manager_callback(callbk: Param,
def get_option_bag(config_bag,
opt,
- callbk,
+ param,
index_,
self_calc,
properties=undefined,
@@ -352,14 +337,14 @@ def manager_callback(callbk: Param,
)
except PropertiesOptionError as err:
# 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 ConfigError(_('unable to carry out a calculation for "{}"'
', {}').format(option.impl_get_display_name(), err), err) from 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
except AttributeError as err:
- if isinstance(callbk, ParamDynOption) and callbk.optional:
+ if isinstance(param, ParamDynOption) and param.optional:
# cannot acces, simulate a propertyerror
raise PropertiesOptionError(options_bag[-1],
['configerror'],
@@ -375,11 +360,11 @@ def manager_callback(callbk: Param,
else:
return options_bag[-1]
- if isinstance(callbk, ParamValue):
- return callbk.value
+ if isinstance(param, ParamValue):
+ return param.value
- if isinstance(callbk, ParamInformation):
- if isinstance(callbk, ParamSelfInformation):
+ if isinstance(param, ParamInformation):
+ if isinstance(param, ParamSelfInformation):
option_bag = OptionBag(option,
index,
config_bag,
@@ -387,48 +372,47 @@ def manager_callback(callbk: Param,
else:
option_bag = None
try:
- return config_bag.context.impl_get_information(config_bag,
- option_bag,
- callbk.information_name,
- callbk.default_value,
+ return config_bag.context.impl_get_information(option_bag,
+ param.information_name,
+ param.default_value,
)
except ValueError as err:
raise ConfigError(_('option "{}" cannot be calculated: {}').format(option.impl_get_display_name(),
str(err),
))
- if isinstance(callbk, ParamIndex):
+ if isinstance(param, ParamIndex):
return index
- if isinstance(callbk, ParamSuffix):
+ if isinstance(param, ParamSuffix):
if not option.issubdyn():
raise ConfigError(_('option "{}" is not in a dynoptiondescription').format(option.impl_get_display_name()))
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:
raise Break()
- value = calc_self(callbk,
+ value = calc_self(param,
option,
index,
orig_value,
config_bag,
)
- if not callbk.todict:
+ if callback.__name__ not in FUNCTION_WAITING_FOR_DICT:
return value
return {'name': option.impl_get_display_name(),
'value': value,
}
- if isinstance(callbk, ParamOption):
- callbk_option = callbk.option
+ if isinstance(param, ParamOption):
+ callbk_option = param.option
callbk_options = None
if callbk_option.issubdyn():
found = False
- if isinstance(callbk, ParamDynOption):
- subdyn = callbk.dynoptiondescription
- rootpath = subdyn.impl_getpath() + callbk.suffix
- suffix = callbk.suffix
+ if isinstance(param, ParamDynOption):
+ subdyn = param.dynoptiondescription
+ rootpath = subdyn.impl_getpath() + param.suffix
+ suffix = param.suffix
callbk_option = callbk_option.to_dynoption(rootpath,
suffix,
subdyn,
@@ -462,8 +446,6 @@ def manager_callback(callbk: Param,
callbk_options.append(doption)
if leadership_must_have_index and callbk_option.impl_is_follower() and index is None:
raise Break()
- if config_bag is undefined:
- return undefined
if callbk_options is None:
callbk_options = [callbk_option]
values = None
@@ -471,7 +453,7 @@ def manager_callback(callbk: Param,
values = []
for callbk_option in callbk_options:
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():
# leader
index_ = None
@@ -486,11 +468,11 @@ def manager_callback(callbk: Param,
path = callbk_option.impl_getpath()
option_bag = get_option_bag(config_bag,
callbk_option,
- callbk,
+ param,
index_,
False,
)
- value = get_value(callbk,
+ value = get_value(param,
option_bag,
path,
)
@@ -500,12 +482,10 @@ def manager_callback(callbk: Param,
values.append(value)
if values is not None:
value = values
- if not callbk.todict:
+ if callback.__name__ not in FUNCTION_WAITING_FOR_DICT:
return value
return {'name': callbk_option.impl_get_display_name(),
'value': value}
- raise ConfigError(_('unknown callback type {} in option {}').format(callbk,
- option.impl_get_display_name()))
def carry_out_calculation(option,
@@ -540,9 +520,10 @@ def carry_out_calculation(option,
args = []
kwargs = {}
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:
- value = manager_callback(callbk,
+ value = manager_callback(callback,
+ param,
option,
index,
orig_value,
@@ -550,16 +531,14 @@ def carry_out_calculation(option,
leadership_must_have_index,
for_settings,
)
- if value is undefined:
- return undefined
if key is None:
args.append(value)
else:
kwargs[key] = value
except PropertiesOptionError as err:
- if callbk.raisepropertyerror:
+ if param.raisepropertyerror:
raise err
- if callbk.todict:
+ if callback.__name__ in FUNCTION_WAITING_FOR_DICT:
if key is None:
args.append({'propertyerror': str(err)})
else:
@@ -616,8 +595,6 @@ def calculate(option,
raise err
error = err
except Exception as err:
- # import traceback
- # traceback.print_exc()
error = err
if args or kwargs:
msg = _('unexpected error "{0}" in function "{1}" with arguments "{3}" and "{4}" '
diff --git a/tiramisu/cacheobj.py b/tiramisu/cacheobj.py
index 2c8cfac..f23d988 100644
--- a/tiramisu/cacheobj.py
+++ b/tiramisu/cacheobj.py
@@ -16,79 +16,91 @@
# along with this program. If not, see .
# ____________________________________________________________
from time import time
-from .log import log
-
-
-def _display_classname(obj): # pragma: no cover
- return(obj.__class__.__name__.lower())
class Cache:
+ """cache object
+ """
__slots__ = ('_cache',)
def __init__(self):
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
if follower, add index
"""
- if 'cache' in props or 'cache' in self_props:
- self._cache.setdefault(path, {})[index] = (val, int(time()), validated)
+ if type_ == 'values':
+ 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):
+ """reset cache a a specified path
+ """
if path in self._cache:
del self._cache[path]
def get_cached(self):
+ """get cache values
+ """
return self._cache
def reset_all_cache(self):
+ """reset all cache values
+ """
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
diff --git a/tiramisu/config.py b/tiramisu/config.py
index 374c5eb..165b5ad 100644
--- a/tiramisu/config.py
+++ b/tiramisu/config.py
@@ -18,16 +18,15 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
-"options handler global entry point"
+"""options handler global entry point
+"""
import weakref
from copy import copy, deepcopy
from typing import Optional, List, Any, Union
-
from .error import PropertiesOptionError, ConfigError, ConflictError, \
LeadershipError
-from .option import SynDynOptionDescription, DynOptionDescription, Leadership, Option
-from .option.baseoption import BaseOption
+from .option import DynOptionDescription, Leadership, Option
from .setting import OptionBag, ConfigBag, Settings, undefined, groups
from .value import Values, owners
from .i18n import _
@@ -48,7 +47,6 @@ class _SubConfig:
def __init__(self,
descr,
context,
- config_bag,
subpath=None,
):
""" Configuration option management class
@@ -60,11 +58,6 @@ class _SubConfig:
:type subpath: `str` with the path name
"""
# 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_context = context
self._impl_path = subpath
@@ -74,16 +67,6 @@ class _SubConfig:
):
"""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.remove_validation()
option_bag = OptionBag(option_bag.option.get_leader(),
@@ -92,22 +75,22 @@ class _SubConfig:
)
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):
+ """get root description
+ """
assert self._impl_descr is not None, _('there is no option description for this config'
' (may be GroupConfig)')
return self._impl_descr
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):
- return self.get_context()._impl_values
+ """get values object
+ """
+ return self._impl_values # pylint: disable=no-member
# =============================================================================
# CACHE
@@ -129,18 +112,24 @@ class _SubConfig:
)
option_bag.config_bag.properties = option_bag.config_bag.properties | {'cache'}
else:
- context = self.get_context()
- context._impl_values_cache.reset_all_cache()
- context.properties_cache.reset_all_cache()
+ self._impl_values_cache.reset_all_cache() # pylint: disable=no-member
+ self.properties_cache.reset_all_cache() # pylint: disable=no-member
+
+ def get_values_cache(self):
+ """get cache for values
+ """
+ return self._impl_values_cache # pylint: disable=no-member
def reset_one_option_cache(self,
resetted_opts,
option_bag,
):
+ """reset cache for one option
+ """
if option_bag.path in resetted_opts:
return
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()
soption_bag = OptionBag(option,
option_bag.index,
@@ -178,7 +167,6 @@ class _SubConfig:
subpath = ''
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,
suffix,
option_bag.option,
@@ -192,7 +180,7 @@ class _SubConfig:
None,
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(),
None,
False,
@@ -258,15 +246,12 @@ class _SubConfig:
:param first: return only one option if True, a list otherwise
: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):
- try:
- value = soption_bag.config_bag.context.get_value(soption_bag)
- except PropertiesOptionError:
- return False
+ value = self.get_value(soption_bag)
if isinstance(value, list):
return byvalue in value
- else:
- return value == byvalue
+ return value == byvalue
found = False
if only_path is not undefined:
@@ -286,10 +271,10 @@ class _SubConfig:
)
if byvalue is not undefined and not _filter_by_value(soption_bag):
continue
- elif option_bag.config_bag.properties:
+ if option_bag.config_bag.properties:
#remove option with propertyerror, ...
try:
- self.get_sub_option_bag(option_bag,
+ self.get_sub_option_bag(option_bag, # pylint: disable=no-member
path,
None,
True,
@@ -331,16 +316,19 @@ class _SubConfig:
return value
def walk(self,
- option_bag,
- types=['option'],
+ option_bag: OptionBag,
+ types: List[str]=('option',),
group_type=None,
- recursive=True,
- walked=False,
+ recursive: bool=True,
+ walked: bool=False,
):
+ """walk to tree
+ """
+ # pylint: disable=too-many-branches,too-many-locals,too-many-arguments,
if option_bag.option.impl_is_optiondescription():
# do not return root option
if walked:
- if 'optiondescription' in types and (group_type is None or
+ if 'optiondescription' in types and (group_type is None or
option_bag.option.impl_get_group_type() == group_type):
yield option_bag
if not recursive:
@@ -349,7 +337,7 @@ class _SubConfig:
if not option_bag.option.impl_is_leadership():
for opt in option_bag.option.get_children(option_bag.config_bag):
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(),
None,
True,
@@ -366,7 +354,7 @@ class _SubConfig:
# it's a leadership so walk to leader and followers
# followers has specific length
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(),
None,
True,
@@ -375,7 +363,7 @@ class _SubConfig:
values = self.get_value(leader_option_bag,
need_help=False,
)
- leadership_length = len(values)
+ ls_length = len(values)
try:
self._walk_valid_value(leader_option_bag,
types,
@@ -383,21 +371,19 @@ class _SubConfig:
)
except PropertiesOptionError as err:
if err.proptype in (['mandatory'], ['empty']):
- if 'mandatory' in types:
- yield leader_option_bag
- else:
- raise err
- for idx in range(leadership_length):
+ yield leader_option_bag
+ for idx in range(ls_length):
followers_dict[idx] = []
for follower in followers:
follower_path = follower.impl_getpath()
try:
- for f_follower_bag in self.walk(self.get_sub_option_bag(option_bag,
- follower_path,
- idx,
- True,
- leadership_length=leadership_length,
- )[-1],
+ options_bag = self.get_sub_option_bag(option_bag, # pylint: disable=no-member
+ follower_path,
+ idx,
+ True,
+ leadership_length=ls_length,
+ )
+ for f_follower_bag in self.walk(options_bag[-1],
types=types,
recursive=recursive,
group_type=group_type,
@@ -410,7 +396,6 @@ class _SubConfig:
continue
if 'option' in types:
yield followers_dict
-# pass
else:
if 'mandatory' in types and not option_bag.option.impl_is_symlinkoption():
try:
@@ -455,25 +440,13 @@ class _SubConfig:
def set_value(self,
option_bag: OptionBag,
value: Any,
- ):
- if option_bag.option.impl_is_symlinkoption():
- raise ConfigError(_("can't set value to a SymLinkOption"))
- context = option_bag.config_bag.context
- context.get_settings().validate_properties(option_bag)
- return context.get_values().set_value(option_bag,
- 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)
+ ) -> Any:
+ """set value
+ """
+ self.get_settings().validate_properties(option_bag)
+ return self.get_values().set_value(option_bag,
+ value
+ )
def get_value(self,
option_bag,
@@ -484,7 +457,9 @@ class _SubConfig:
:return: option's value if name is an option name, OptionDescription
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):
value = []
for opt_bag in option_bag:
@@ -507,10 +482,10 @@ class _SubConfig:
return value
def _get(self,
- option_bag,
- parent_option_bag,
- need_help,
- ):
+ option_bag: OptionBag,
+ need_help: bool,
+ ) -> OptionBag:
+ # pylint: disable=too-many-locals
option = option_bag.option
if option.impl_is_symlinkoption():
suboption = option.impl_getopt()
@@ -534,7 +509,7 @@ class _SubConfig:
ret.append(doption_bag)
return ret
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(),
None,
True,
@@ -554,40 +529,28 @@ class _SubConfig:
option_bag.config_bag,
ori_option=option,
)
- return self._get(soption_bag, None, need_help)
+ return self._get(soption_bag,
+ need_help,
+ )
return option_bag
- def get_owner(self,
- option_bag: OptionBag,
- parent_option_bag=None,
- ):
- options_bag = self._get(option_bag, parent_option_bag, need_help=True)
+ def get_owner(self, option_bag: OptionBag):
+ """get owner
+ """
+ options_bag = self._get(option_bag,
+ need_help=True,
+ )
if isinstance(options_bag, list):
- if not option_bag.option.impl_is_symlinkoption():
- owner = []
- for opt_bag in options_bag:
- owner.append(self.get_owner(opt_bag))
+ for opt_bag in options_bag:
+ owner = self.get_owner(opt_bag)
+ if owner != owners.default:
+ break
else:
- for opt_bag in options_bag:
- owner = self.get_owner(opt_bag)
- if owner != owners.default:
- break
- else:
- owner = owners.default
+ owner = owners.default
else:
owner = self.get_values().getowner(options_bag)
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):
"abstract base class for the Config, KernelGroupConfig and the KernelMetaConfig"
@@ -597,18 +560,21 @@ class _CommonConfig(_SubConfig):
'properties_cache',
'_impl_permissives_cache',
'parents',
- 'impl_type')
+ 'impl_type',
+ )
def _impl_build_all_caches(self, descr):
if not descr.impl_already_build_caches():
- descr._group_type = groups.root
- descr._build_cache(display_name=self._display_name)
+ descr._group_type = groups.root # pylint: disable=protected-access
+ descr._build_cache(display_name=self._display_name) # pylint: disable=no-member,protected-access
if not hasattr(descr, '_cache_force_store_values'):
raise ConfigError(_('option description seems to be part of an other '
'config'))
def get_parents(self):
- for parent in self.parents:
+ """get parents
+ """
+ for parent in self.parents: # pylint: disable=no-member
yield parent()
# information
@@ -622,22 +588,19 @@ class _CommonConfig(_SubConfig):
:param key: information's key (ex: "help", "doc"
:param value: information's value (ex: "the help string")
"""
- self._impl_values.set_information(config_bag,
- None,
- key,
- value,
- )
- context = config_bag.context
- cache = context.get_description()._cache_dependencies_information.get(key, [])
+ self._impl_values.set_information(None, # pylint: disable=no-member
+ key,
+ value,
+ )
+ cache = self.get_description()._cache_dependencies_information.get(key, []) # pylint: disable=protected-access
for option in cache:
option_bag = OptionBag(option,
None,
config_bag,
)
- context.reset_cache(option_bag)
+ self.reset_cache(option_bag)
def impl_get_information(self,
- config_bag,
option_bag,
key,
default,
@@ -646,8 +609,7 @@ class _CommonConfig(_SubConfig):
:param key: the item string (ex: "help")
"""
- return self._impl_values.get_information(config_bag,
- option_bag,
+ return self._impl_values.get_information(option_bag, # pylint: disable=no-member
key,
default,
)
@@ -656,24 +618,27 @@ class _CommonConfig(_SubConfig):
key,
raises=True,
):
- self._impl_values.del_information(key,
+ """delete an information
+ """
+ self._impl_values.del_information(key, # pylint: disable=no-member
raises,
)
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):
- raise NotImplementedError()
-
- def _gen_fake_values(self):
- export = deepcopy(self.get_values()._values)
+ def gen_fake_values(self) -> 'KernelConfig':
+ """generate a fake values to improve validation when assign a new value
+ """
+ export = deepcopy(self.get_values()._values) # pylint: disable=protected-access
fake_config = KernelConfig(self._impl_descr,
force_values=export,
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
def duplicate(self,
@@ -684,10 +649,11 @@ class _CommonConfig(_SubConfig):
deep=None,
name=None,
):
- if not isinstance(self, (KernelConfig, KernelMixConfig)):
- raise ConfigError(_('cannot duplicate {}').format(self.__class__.__name__))
+ """duplication config
+ """
+ # pylint: disable=too-many-arguments
if name is None:
- name = self._impl_name
+ name = self._impl_name # pylint: disable=no-member
if isinstance(self, KernelConfig):
duplicated_config = KernelConfig(self._impl_descr,
_duplicate=True,
@@ -703,10 +669,10 @@ class _CommonConfig(_SubConfig):
)
duplicated_values = duplicated_config.get_values()
duplicated_settings = duplicated_config.get_settings()
- duplicated_values._values = deepcopy(self.get_values()._values)
- duplicated_values._informations = deepcopy(self.get_values()._informations)
- duplicated_settings._properties = deepcopy(self.get_settings()._properties)
- duplicated_settings._permissives = deepcopy(self.get_settings()._permissives)
+ duplicated_values._values = deepcopy(self.get_values()._values) # pylint: disable=protected-access
+ duplicated_values._informations = deepcopy(self.get_values()._informations) # pylint: disable=protected-access
+ duplicated_settings._properties = deepcopy(self.get_settings()._properties) # pylint: disable=protected-access
+ duplicated_settings._permissives = deepcopy(self.get_settings()._permissives) # pylint: disable=protected-access
duplicated_settings.ro_append = self.get_settings().ro_append
duplicated_settings.rw_append = self.get_settings().rw_append
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_config.reset_cache(None, 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))
- if self.parents:
+ if self.parents: # pylint: disable=no-member
if deep is not None:
- for parent in self.parents:
+ for parent in self.parents: # pylint: disable=no-member
wparent = parent()
if wparent not in deep:
deep.append(wparent)
@@ -731,17 +697,19 @@ class _CommonConfig(_SubConfig):
name=subname,
)
else:
- duplicated_config.parents = self.parents
- for parent in self.parents:
- parent()._impl_children.append(duplicated_config)
+ duplicated_config.parents = self.parents # pylint: disable=no-member
+ for parent in self.parents: # pylint: disable=no-member
+ parent()._impl_children.append(duplicated_config) # pylint: disable=protected-access
return duplicated_config
def get_config_path(self):
+ """get config path
+ """
path = self.impl_getname()
- for parent in self.parents:
+ for parent in self.parents: # pylint: disable=no-member
wparent = parent()
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
return path
@@ -755,6 +723,7 @@ class _CommonConfig(_SubConfig):
) -> List[OptionBag]:
"""Get the suboption for path and the name of the option
:returns: tuple (config, name)"""
+ # pylint: disable=too-many-branches,too-many-locals,too-many-arguments
if isinstance(bag, ConfigBag):
option_bag = OptionBag(self.get_description(),
None,
@@ -763,8 +732,6 @@ class _CommonConfig(_SubConfig):
else:
option_bag = bag
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.split('.')
last_idx = len(path) - 1
@@ -789,17 +756,18 @@ class _CommonConfig(_SubConfig):
option_index = None
if idx == last_idx:
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')
if leadership_length is not None:
length = leadership_length
else:
length = self.get_length_leadership(sub_option_bag)
if index >= length:
- raise LeadershipError(_('index "{}" is greater than the leadership length "{}" '
- 'for option "{}"').format(index,
- length,
- option.impl_get_display_name()))
+ raise LeadershipError(_(f'index "{index}" is greater than the leadership '
+ f'length "{length}" for option '
+ f'"{option.impl_get_display_name()}"'))
option_properties = properties
else:
option_properties = undefined
@@ -815,17 +783,22 @@ class _CommonConfig(_SubConfig):
return options_bag
def impl_getname(self):
- return self._impl_name
+ """get config name
+ """
+ return self._impl_name # pylint: disable=no-member
# ____________________________________________________________
class KernelConfig(_CommonConfig):
- "main configuration management entry"
+ """main configuration management entry
+ """
+ # pylint: disable=too-many-instance-attributes
__slots__ = ('__weakref__',
'_impl_name',
'_display_name',
'_impl_symlink',
- '_storage')
+ '_storage',
+ )
impl_type = 'config'
def __init__(self,
@@ -843,6 +816,7 @@ class KernelConfig(_CommonConfig):
:param context: the current root config
:type context: `Config`
"""
+ # pylint: disable=too-many-arguments,too-many-arguments
self._display_name = display_name
self.parents = []
self._impl_symlink = []
@@ -870,11 +844,12 @@ class KernelConfig(_CommonConfig):
super().__init__(descr,
self._impl_context,
None,
- None,
)
class KernelGroupConfig(_CommonConfig):
+ """Group a config with same optiondescription tree
+ """
__slots__ = ('__weakref__',
'_impl_children',
'_impl_name',
@@ -886,18 +861,15 @@ class KernelGroupConfig(_CommonConfig):
children,
display_name=None,
name=None,
- _descr=None):
- if not isinstance(children, list):
- raise ConfigError(_("groupconfig's children must be a list"))
+ _descr=None,
+ ):
+ # pylint: disable=super-init-not-called
names = []
for child in children:
- if not isinstance(child, _CommonConfig):
- raise ConfigError(_("groupconfig's children must be Config, MetaConfig or "
- "GroupConfig"))
name_ = child._impl_name
names.append(name_)
if len(names) != len(set(names)):
- for idx in range(1, len(names) + 1):
+ while range(1, len(names) + 1):
name = names.pop(0)
if name in names:
raise ConflictError(_('config name must be uniq in '
@@ -905,9 +877,6 @@ class KernelGroupConfig(_CommonConfig):
self._impl_children = children
self.parents = []
- config_bag = ConfigBag(self,
- properties=None,
- permissives=None)
self._display_name = display_name
if name:
self._impl_name = name
@@ -916,6 +885,8 @@ class KernelGroupConfig(_CommonConfig):
self._impl_path = None
def get_children(self):
+ """get all children
+ """
return self._impl_children
def reset_cache(self,
@@ -972,6 +943,7 @@ class KernelGroupConfig(_CommonConfig):
value,
)
except PropertiesOptionError as err:
+ # pylint: disable=protected-access
ret.append(PropertiesOptionError(err._option_bag,
err.proptype,
err._settings,
@@ -994,6 +966,7 @@ class KernelGroupConfig(_CommonConfig):
):
"""Find first not in current KernelGroupConfig, but in each children
"""
+ # pylint: disable=too-many-arguments
# if KernelMetaConfig, all children have same OptionDescription in
# context so search only one time the option for all children
if bypath is undefined and byname is not None and \
@@ -1002,14 +975,13 @@ class KernelGroupConfig(_CommonConfig):
None,
config_bag,
)
- for bypath, byoption in self.find(root_option_bag,
- bytype=None,
- byname=byname,
- byvalue=undefined,
- raise_if_not_found=raise_if_not_found,
- with_option=True,
- ):
- break
+ next(self.find(root_option_bag,
+ bytype=None,
+ byname=byname,
+ byvalue=undefined,
+ raise_if_not_found=raise_if_not_found,
+ with_option=True,
+ ))
byname = None
ret = []
@@ -1035,25 +1007,30 @@ class KernelGroupConfig(_CommonConfig):
None,
cconfig_bag,
)
- for path in child.find(root_option_bag,
- None,
- byname,
- byvalue,
- raise_if_not_found=False,
- only_path=bypath,
- only_option=byoption,
- ):
+ try:
+ next(child.find(root_option_bag,
+ None,
+ byname,
+ byvalue,
+ raise_if_not_found=False,
+ only_path=bypath,
+ only_option=byoption,
+ ))
ret.append(child)
- break
+ except StopIteration:
+ pass
if not _sub:
- self._find_return_results(ret != [],
- raise_if_not_found)
+ self._find_return_results(ret != [], # pylint: disable=use-implicit-booleaness-not-comparison
+ raise_if_not_found,
+ )
return ret
def reset(self,
path: str,
config_bag: ConfigBag,
- ):
+ ) -> None:
+ """reset value for specified path
+ """
for child in self._impl_children:
settings = child.get_settings()
cconfig_bag = config_bag.copy()
@@ -1072,7 +1049,10 @@ class KernelGroupConfig(_CommonConfig):
child.get_values().reset(option_bag)
def getconfig(self,
- name):
+ name: str,
+ ) -> KernelConfig:
+ """get a child from a config name
+ """
for child in self._impl_children:
if name == child.impl_getname():
return child
@@ -1080,9 +1060,12 @@ class KernelGroupConfig(_CommonConfig):
class KernelMixConfig(KernelGroupConfig):
- __slots__ = ('_impl_name',
- '_impl_symlink',
- '_storage')
+ """Kernel mixconfig: this config can have differents optiondescription tree
+ """
+ # pylint: disable=too-many-instance-attributes
+ __slots__ = ('_impl_symlink',
+ '_storage',
+ )
impl_type = 'mix'
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
this KernelMetaConfig
"""
+ # pylint: disable=too-many-branches,too-many-nested-blocks,too-many-locals,too-many-arguments
ret = []
if only_config:
if force_default or force_default_if_same or force_dont_change_value:
@@ -1147,10 +1131,11 @@ class KernelMixConfig(KernelGroupConfig):
obj = self
else:
obj = child
+ validate_properties = not force_default and not force_default_if_same
moption_bag = obj.get_sub_option_bag(cconfig_bag,
option_bag.path,
option_bag.index,
- not force_default and not force_default_if_same,
+ validate_properties,
)[-1]
if force_default_if_same:
if not child.get_values().hasvalue(option_bag.path):
@@ -1167,6 +1152,7 @@ class KernelMixConfig(KernelGroupConfig):
child_value,
)
except PropertiesOptionError as err:
+ # pylint: disable=protected-access
ret.append(PropertiesOptionError(err._option_bag,
err.proptype,
err._settings,
@@ -1198,10 +1184,13 @@ class KernelMixConfig(KernelGroupConfig):
return ret
def reset(self,
- path,
- only_children,
- config_bag,
- ):
+ path: str,
+ only_children: bool,
+ config_bag: ConfigBag,
+ ) -> None:
+ """reset value for a specified path
+ """
+ # pylint: disable=arguments-differ
rconfig_bag = config_bag.copy()
rconfig_bag.remove_validation()
if self.impl_type == 'meta':
@@ -1338,8 +1327,8 @@ class KernelMetaConfig(KernelMixConfig):
new_children = []
for child_name in children:
assert isinstance(child_name, str), _('MetaConfig with optiondescription'
- ' must have string has child, '
- 'not {}').format(child_name)
+ ' must have string has child, '
+ 'not {}').format(child_name)
new_children.append(KernelConfig(optiondescription, name=child_name))
children = new_children
descr = optiondescription
diff --git a/tiramisu/function.py b/tiramisu/function.py
index 0b8b2f2..4ae7ef3 100644
--- a/tiramisu/function.py
+++ b/tiramisu/function.py
@@ -12,6 +12,8 @@
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
+"""some functions to validates or calculates value
+"""
from typing import Any, List, Optional
from operator import add, mul, sub, truediv
from ipaddress import ip_address, ip_interface, ip_network
@@ -20,145 +22,130 @@ from .setting import undefined
from .error import display_list
-def valid_network_netmask(network: str,
- netmask: str):
- """FIXME
+FUNCTION_WAITING_FOR_DICT = []
+
+
+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):
- network_value = network['value']
- network_display_name = '({})'.format(network['name'])
- else:
- network_value = network
- network_display_name = ''
- if None in [network_value, netmask]:
+ name = function.__name__
+ if name not in FUNCTION_WAITING_FOR_DICT:
+ FUNCTION_WAITING_FOR_DICT.append(name)
+ return function
+
+
+@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
try:
- ip_network('{0}/{1}'.format(network_value, netmask))
- except ValueError:
- raise ValueError(_('network "{0}" {1}does not match with this netmask').format(network_value,
- network_display_name))
+ ip_network(f'{network["value"]}/{netmask["value"]}')
+ except ValueError as err:
+ raise ValueError(_(f'network "{network["value"]}" ({network["name"]}) does not match '
+ 'with this netmask')) from err
-def valid_ip_netmask(ip: str,
- netmask: str):
- if isinstance(ip, dict):
- ip_value = ip['value']
- ip_display_name = '({})'.format(ip['name'])
- else:
- ip_value = ip
- ip_display_name = ''
- if None in [ip_value, netmask]:
+
+@function_waiting_for_dict
+def valid_ip_netmask(ip: dict, # pylint: disable=invalid-name
+ netmask: dict,
+ ):
+ """validates if ip and netmask are coherent
+ this validator must be set to netmask option
+ """
+ if None in [ip['value'], netmask['value']]:
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:
- raise ValueError(_('IP \"{0}\" {1}with this netmask is in fact a network address').format(ip_value, ip_display_name))
- elif ip_netmask.ip == ip_netmask.network.broadcast_address:
- raise ValueError(_('IP \"{0}\" {1}with this netmask is in fact a broacast address').format(ip_value, ip_display_name))
+ msg = _(f'IP "{ip["value"]}" ({ip["name"]}) with this netmask is '
+ 'in fact a network address')
+ 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 ?
-def valid_broadcast(network: 'NetworkOption',
- netmask: 'NetmaskOption',
- broadcast: 'BroadcastOption'):
- 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 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:
+@function_waiting_for_dict
+def valid_broadcast(network: dict,
+ netmask: dict,
+ broadcast: dict,
+ ):
+ """validates if the broadcast is coherent with network and netmask
+ """
+ if None in [network['value'], netmask['value'], broadcast['value']]:
return
- if '/' in network_value:
- network_obj = ip_network('{0}'.format(network_value))
+ if ip_network(f'{network["value"]}/{netmask["value"]}').broadcast_address != \
+ 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:
- if netmask_value is None:
+ if netmask is None or netmask['value'] is None:
return
- network_obj = ip_network('{0}/{1}'.format(network_value,
- netmask_value))
- if ip_interface(ip) not in network_obj:
+ network_value = f'{network["value"]}/{netmask["value"]}'
+ network_obj = ip_network(network_value)
+ ip_netmask = ip_interface(f'{ip["value"]}/{network_obj.netmask}')
+ if ip_netmask not in network_obj:
if netmask is None:
- msg = _('this IP is not in network {0}{1}').format(network_value,
- network_display_name)
+ msg = _('this IP is not in network {network["value"]} ({network["name"]})')
else:
- msg = _('this IP is not in network {0}{1} with netmask {2}{3}').format(network_value,
- network_display_name,
- netmask_value,
- netmask_display_name)
+ msg = _('this IP is not in network {network["value"]} ({network["name"]}) '
+ 'with netmask {netmask["value"]} ({netmask["name"]})')
raise ValueError(msg)
-
# 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 netmask is None:
- msg = _('this IP with the network {0}{1} is in fact a network address').format(network_value,
- network_display_name)
- else:
- msg = _('this IP with the netmask {0}{1} is in fact a network address').format(netmask_value,
- netmask_display_name)
+ msg = _(f'this IP with the network {network["value"]} ({network["value"]} '
+ 'is in fact a network address')
raise ValueError(msg)
- elif ip_netmask.ip == ip_netmask.network.broadcast_address:
- if netmask is None:
- msg = _('this IP with the network {0}{1} is in fact a broadcast address').format(network_value,
- network_display_name)
- else:
- msg = _('this IP with the netmask {0}{1} is in fact a broadcast address').format(netmask_value,
- netmask_display_name)
+ if ip_netmask.ip == ip_netmask.network.broadcast_address:
+ msg = _(f'this IP with the network {network["value"]} ({network["value"]} '
+ 'is in fact a broadcast address')
raise ValueError(msg)
+@function_waiting_for_dict
def valid_not_equal(*values):
+ """valid that two options have not same value
+ """
equal = set()
- for idx, val in enumerate(values[1:]):
- if isinstance(val, dict):
- if 'propertyerror' in val:
- continue
- tval = val['value']
- else:
- tval = val
- if values[0] == tval is not None:
- if isinstance(val, dict):
- 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)
+ for val in values[1:]:
+ if 'propertyerror' in val:
+ continue
+ if values[0]['value'] == val['value'] is not None:
+ equal.add(val['name'])
+ if not equal:
+ return
+ msg = _(f'value is identical to {display_list(list(equal), add_quote=True)}')
+ raise ValueError(msg)
class CalcValue:
+ """class to calc_value with different functions
+ """
+ # pylint: disable=too-many-instance-attributes
def __call__(self,
*args: List[Any],
multi: bool=False,
@@ -175,6 +162,7 @@ class CalcValue:
operator: Optional[str]=None,
index: Optional[int]=None,
**kwargs) -> Any:
+ # pylint: disable=too-many-statements,too-many-branches,too-many-nested-blocks,too-many-locals
"""calculate value
:param args: 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
if there is more than one condition, set condition_0, condition_1, ...
: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
- 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 allow_none: if False, do not return list in None is present in list
:param remove_duplicate_value: if True, remote duplicated value
@@ -196,28 +186,36 @@ class CalcValue:
examples:
* 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')
- >>> 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])
>>> cfg = Config(od)
>>> cfg.value.dict()
{'val1': 'val1', 'val2': 'val1'}
* 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')
>>> 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])
>>> cfg = Config(od)
>>> cfg.value.dict()
{'val1': 'val1', 'val2': 'val2', 'val3': ['val1', 'val2']}
* 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')
- >>> 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])
>>> cfg = Config(od)
>>> cfg.property.read_write()
@@ -228,13 +226,15 @@ class CalcValue:
{'val2': '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)
>>> val1 = StrOption('val1', '', 'val1')
- >>> val2 = StrOption('val2', '', callback=calc_value, callback_params=Params(ParamOption(val1, True),
- ... default=ParamValue('default_value'),
- ... condition=ParamOption(boolean),
- ... expected=ParamValue(True)))
+ >>> val2 = StrOption('val2', '', callback=calc_value,
+ ... callback_params=Params(ParamOption(val1, True),
+ ... default=ParamValue('default_value'),
+ ... condition=ParamOption(boolean),
+ ... expected=ParamValue(True)))
>>> od = OptionDescription('root', '', [boolean, val1, val2])
>>> cfg = Config(od)
>>> cfg.property.read_write()
@@ -245,41 +245,55 @@ class CalcValue:
{'boolean': False, 'val1': 'val1', 'val2': 'default_value'}
* 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')
>>> 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])
>>> cfg = Config(od)
>>> cfg.value.dict()
{'val1': 'val1', 'val2': None, 'val3': ['val1', None]}
* 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')
>>> 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])
>>> cfg = Config(od)
>>> cfg.value.dict()
{'val1': 'val1', 'val2': 'val1', 'val3': ['val1']}
* 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')
>>> 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])
>>> cfg = Config(od)
>>> cfg.value.dict()
{'val1': 'val1', 'val2': 'val2', 'val3': 'val1.val2'}
* 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')
>>> val2 = StrOption('val2', "", 'val2')
>>> 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])
>>> cfg = Config(od)
>>> cfg.property.read_write()
@@ -290,25 +304,31 @@ class CalcValue:
{'val1': 'val1', 'val2': 'val2', 'val4': ''}
* 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)
>>> 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])
>>> cfg = Config(od)
>>> cfg.value.dict()
{'val1': 1, 'val2': 2, 'val3': 3}
"""
+ # pylint: disable=attribute-defined-outside-init
self.args = args
self.condition = condition
self.expected = expected
self.condition_operator = condition_operator
self.reverse_condition = reverse_condition
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,
- min_args_len)
+ min_args_len,
+ )
if not multi:
if join is not None:
if None not in value:
@@ -317,12 +337,13 @@ class CalcValue:
value = None
elif value and operator:
new_value = value[0]
- op = {'mul': mul,
- 'add': add,
- 'div': truediv,
- 'sub': sub}[operator]
+ oper = {'mul': mul,
+ 'add': add,
+ 'div': truediv,
+ 'sub': sub,
+ }[operator]
for val in value[1:]:
- new_value = op(new_value, val)
+ new_value = oper(new_value, val)
value = new_value
elif value == []:
value = None
@@ -344,7 +365,9 @@ class CalcValue:
break
lval = len(val)
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
new_value = []
if length_val is not None:
@@ -374,6 +397,9 @@ class CalcValue:
pattern: str,
to_dict: bool=False,
empty_test=undefined) -> Any:
+ """get value from kwargs
+ """
+ # pylint: disable=too-many-branches
# if value attribute exist return it's value
# otherwise pattern_0, pattern_1, ...
# otherwise undefined
@@ -385,10 +411,9 @@ class CalcValue:
else:
kwargs_matches = {}
len_pattern = len(pattern)
- for key in self.kwargs.keys():
+ for key, pattern_value in self.kwargs.items():
if key.startswith(pattern):
index = int(key[len_pattern:])
- pattern_value = self.kwargs[key]
if isinstance(pattern_value, dict):
pattern_value = pattern_value['value']
kwargs_matches[index] = pattern_value
@@ -408,21 +433,28 @@ class CalcValue:
return returns
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,
'condition_',
- to_dict='all')
+ to_dict='all',
+ )
if calculated_conditions is undefined:
is_matches = not self.no_condition_is_invalid
else:
is_matches = None
calculated_expected = self.value_from_kwargs(self.expected,
'expected_',
- to_dict=True)
+ to_dict=True,
+ )
calculated_reverse = self.value_from_kwargs(self.reverse_condition,
'reverse_condition_',
to_dict=True,
- empty_test=False)
+ empty_test=False,
+ )
for idx, calculated_condition in calculated_conditions.items():
if isinstance(calculated_expected, dict):
if idx is not None:
@@ -453,14 +485,20 @@ class CalcValue:
if is_matches:
break
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 \
or not is_matches and self.reverse_condition
return is_matches
def get_value(self,
default,
- min_args_len):
+ min_args_len,
+ ):
+ """get the value from arguments
+ """
+ # retrieve the condition
if isinstance(self.condition, dict):
if 'value' in self.condition:
condition_value = self.condition['value']
@@ -468,18 +506,19 @@ class CalcValue:
condition_value = undefined
else:
condition_value = self.condition
- condition_matches = self.is_condition_matches(condition_value)
- if not condition_matches:
- # force to default
+ # value is empty if condition doesn't match
+ # otherwise value is arg
+ if not self.is_condition_matches(condition_value):
value = []
else:
value = self.get_args()
if min_args_len and not len(value) >= min_args_len:
value = []
- if value == []:
+ if not value:
# default value
new_default = self.value_from_kwargs(default,
- 'default_')
+ 'default_',
+ )
if new_default is not undefined:
if not isinstance(new_default, list):
value = [new_default]
@@ -488,29 +527,34 @@ class CalcValue:
return value
def get_args(self):
+ """get all arguments
+ """
return list(self.args)
class CalcValuePropertyHelp(CalcValue):
+ """special class to display property error
+ """
def get_name(self):
+ """get the condition name
+ """
return self.condition['name']
- def get_indexed_name(self, index):
- return self.kwargs.get(f'condition_{index}')['name']
+ def get_indexed_name(self, index: int) -> str:
+ """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):
- #if isinstance(option, tuple):
- # if not reverse:
- # msg = _('the calculated value is {0}').format(display_value)
- # else:
- # msg = _('the calculated value is not {0}').format(display_value)
- #else:
+ def build_property_message(self,
+ name: str,
+ value: Any,
+ ) -> str:
+ """prepare message to display error message if needed
+ """
if not self.reverse_condition:
msg = _('the value of "{0}" is {1}').format(name, value)
else:
@@ -519,40 +563,35 @@ class CalcValuePropertyHelp(CalcValue):
def get_args(self):
args = super().get_args()
- if args:
- if len(self.args) != 1:
- raise ValueError(_('only one property is allowed for a calculation'))
- action = args[0]
- calculated_expected = self.value_from_kwargs(self.expected,
- 'expected_',
- to_dict=True)
- 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())
+ action = args[0]
+ calculated_expected = self.value_from_kwargs(self.expected,
+ 'expected_',
+ to_dict=True)
+ if self.condition is not undefined:
+ if 'propertyerror' in self.condition:
+ msg = self.condition['propertyerror']
else:
- return [(action, f'"{action}"')]
- return [(action, f'"{action}" ({msg})')]
- return
- ## calc_properties.setdefault(action, []).append(msg)
+ 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_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.__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.__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)
diff --git a/tiramisu/log.py b/tiramisu/log.py
index 178f5b6..22c3005 100644
--- a/tiramisu/log.py
+++ b/tiramisu/log.py
@@ -15,7 +15,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
# ____________________________________________________________
-from logging import getLogger, DEBUG, basicConfig, StreamHandler, Formatter
+from logging import getLogger, DEBUG, StreamHandler, Formatter
import os
diff --git a/tiramisu/option/__init__.py b/tiramisu/option/__init__.py
index b55ce22..9a2938c 100644
--- a/tiramisu/option/__init__.py
+++ b/tiramisu/option/__init__.py
@@ -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 .
+#
+# 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 .dynoptiondescription import DynOptionDescription
from .syndynoptiondescription import SynDynOptionDescription, SynDynLeadership
diff --git a/tiramisu/option/baseoption.py b/tiramisu/option/baseoption.py
index 31f686a..d7803cc 100644
--- a/tiramisu/option/baseoption.py
+++ b/tiramisu/option/baseoption.py
@@ -18,18 +18,16 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
-from types import FunctionType
-from typing import FrozenSet, Callable, Tuple, Set, Optional, Union, Any, List
+"""base option
+"""
+from typing import FrozenSet, Set, Any, List
import weakref
-from inspect import signature
from itertools import chain
from ..i18n import _
-from ..setting import undefined, Settings
-from ..value import Values
-from ..error import ConfigError, display_list
-from ..autolib import Calculation, Params, ParamOption
+from ..setting import undefined
+from ..autolib import Calculation, ParamOption
STATIC_TUPLE = frozenset()
@@ -38,6 +36,8 @@ submulti = 2
def valid_name(name):
+ """valid option name
+ """
if not isinstance(name, str):
return False
# if '.' in name:
@@ -73,7 +73,8 @@ class Base:
elif isinstance(properties, tuple):
properties = frozenset(properties)
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
if 'notunique' not in properties:
properties = properties | {'unique'}
@@ -85,7 +86,8 @@ class Base:
for prop in properties:
if not isinstance(prop, str):
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()):
if isinstance(param, ParamOption):
param.option._add_dependency(self)
@@ -96,7 +98,10 @@ class Base:
_setattr(self, '_properties', properties)
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:
return getattr(self, '_has_dependency', False)
return hasattr(self, '_dependencies')
@@ -107,7 +112,7 @@ class Base:
ret = set(getattr(self, '_dependencies', STATIC_TUPLE))
if context_od and hasattr(context_od, '_dependencies'):
# 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
def _get_suffixes_dependencies(self) -> Set[str]:
@@ -119,26 +124,32 @@ class Base:
) -> None:
woption = weakref.ref(option)
options = self._get_dependencies(None)
- options.add(weakref.ref(option))
- self._dependencies = tuple(options)
+ options.add(woption)
+ self._dependencies = tuple(options) # pylint: disable=attribute-defined-outside-init
if is_suffix:
options = list(self._get_suffixes_dependencies())
- options.append(weakref.ref(option))
- self._suffixes_dependencies = tuple(options)
+ options.append(woption)
+ self._suffixes_dependencies = tuple(options) # pylint: disable=attribute-defined-outside-init
def impl_is_optiondescription(self) -> bool:
+ """option is an option description
+ """
return False
def impl_is_dynoptiondescription(self) -> bool:
+ """option is not a dyn option description
+ """
return False
def impl_getname(self) -> str:
- return self._name
+ """get name
+ """
+ return self._name # pylint: disable=no-member
def _set_readonly(self) -> None:
- if isinstance(self._informations, dict):
+ if isinstance(self._informations, dict): # pylint: disable=no-member
_setattr = object.__setattr__
- dico = self._informations
+ dico = self._informations # pylint: disable=no-member
keys = tuple(dico.keys())
if len(keys) == 1:
dico = dico['doc']
@@ -150,21 +161,30 @@ class Base:
_setattr(self, '_extra', tuple([tuple(extra.keys()), tuple(extra.values())]))
def impl_is_readonly(self) -> str:
+ """the option is readonly
+ """
# _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]:
+ """get properties
+ """
return getattr(self, '_properties', frozenset())
def _setsubdyn(self,
subdyn,
) -> None:
+ # pylint: disable=attribute-defined-outside-init
self._subdyn = subdyn
def issubdyn(self) -> bool:
+ """is sub dynoption
+ """
return getattr(self, '_subdyn', None) is not None
def getsubdyn(self):
+ """get sub dynoption
+ """
return self._subdyn()
# ____________________________________________________________
@@ -177,7 +197,7 @@ class Base:
:param key: the item string (ex: "help")
"""
- dico = self._informations
+ dico = self._informations # pylint: disable=no-member
if isinstance(dico, tuple):
if key in dico[0]:
return dico[1][dico[0].index(key)]
@@ -189,7 +209,9 @@ class Base:
return dico[key]
if default is not undefined:
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,
key: str,
@@ -206,13 +228,15 @@ class Base:
" read-only").format(self.__class__.__name__,
self,
key))
- self._informations[key] = value
+ self._informations[key] = value # pylint: disable=no-member
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):
return list(dico[0])
- elif isinstance(dico, str):
+ if isinstance(dico, str):
return ['doc']
# it's a dict
return list(dico.keys())
@@ -225,9 +249,6 @@ class BaseOption(Base):
"""
__slots__ = ('_display_name_function',)
- def __getstate__(self):
- raise NotImplementedError()
-
def __setattr__(self,
name: str,
value: Any) -> Any:
@@ -245,19 +266,16 @@ class BaseOption(Base):
' read-only').format(self.__class__.__name__,
self.impl_get_display_name(),
name))
- super(BaseOption, self).__setattr__(name, value)
+ super().__setattr__(name, value)
def impl_getpath(self) -> str:
+ """get the path of the option
+ """
try:
return self._path
- except AttributeError:
- raise AttributeError(_('"{}" not part of any Config').format(self.impl_get_display_name()))
-
- 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
+ except AttributeError as err:
+ raise AttributeError(_(f'"{self.impl_get_display_name()}" not part of any Config')) \
+ from err
def _impl_get_display_name(self,
dyn_name: Base=None,
@@ -287,6 +305,8 @@ class BaseOption(Base):
)
def impl_get_display_name(self) -> str:
+ """get display name
+ """
return self._get_display_name(None,
None,
)
@@ -294,19 +314,26 @@ class BaseOption(Base):
def reset_cache(self,
path: str,
config_bag: 'OptionBag',
- resetted_opts: List[Base]) -> None:
+ resetted_opts: List[Base], # pylint: disable=unused-argument
+ ) -> None:
+ """reset cache
+ """
context = config_bag.context
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():
- context._impl_values_cache.delcache(path)
+ context.get_values_cache().delcache(path) # pylint: disable=protected-access
def impl_is_symlinkoption(self) -> bool:
+ """the option is not a symlinkoption
+ """
return False
def get_dependencies_information(self,
itself=False,
) -> List[str]:
+ """get dependencies information
+ """
if itself:
idx = 1
else:
diff --git a/tiramisu/option/booloption.py b/tiramisu/option/booloption.py
index 7beffef..ebbba2d 100644
--- a/tiramisu/option/booloption.py
+++ b/tiramisu/option/booloption.py
@@ -18,19 +18,23 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
+"""BoolOption
+"""
-from ..setting import undefined, Undefined, OptionBag
from ..i18n import _
from .option import Option
class BoolOption(Option):
- "represents a choice between ``True`` and ``False``"
+ """represents a choice between ``True`` and ``False``
+ """
__slots__ = tuple()
- _type = 'boolean'
- _display_name = _('boolean')
+ _type = _('boolean')
def validate(self,
- value: bool) -> None:
+ value: bool,
+ ) -> None:
+ """validate value
+ """
if not isinstance(value, bool):
raise ValueError()
diff --git a/tiramisu/option/broadcastoption.py b/tiramisu/option/broadcastoption.py
index 941769d..52423d4 100644
--- a/tiramisu/option/broadcastoption.py
+++ b/tiramisu/option/broadcastoption.py
@@ -18,21 +18,25 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# 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 .option import Option
class BroadcastOption(Option):
+ """represents the choice of a broadcast
+ """
__slots__ = tuple()
- _type = 'broadcast_address'
- _display_name = _('broadcast address')
+ _type = _('broadcast address')
def validate(self,
- value: str) -> None:
+ value: str,
+ ) -> None:
+ """validate
+ """
if not isinstance(value, str):
raise ValueError(_('invalid string'))
if value.count('.') != 3:
@@ -42,5 +46,5 @@ class BroadcastOption(Option):
raise ValueError()
try:
ip_address(value)
- except ValueError:
- raise ValueError()
+ except ValueError as err:
+ raise ValueError() from err
diff --git a/tiramisu/option/choiceoption.py b/tiramisu/option/choiceoption.py
index 61fdb52..49a5b5c 100644
--- a/tiramisu/option/choiceoption.py
+++ b/tiramisu/option/choiceoption.py
@@ -18,6 +18,8 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
+"""ChoiceOption
+"""
from typing import Any
from ..setting import undefined, OptionBag
@@ -33,8 +35,7 @@ class ChoiceOption(Option):
The option can also have the value ``None``
"""
__slots__ = tuple()
- _type = 'choice'
- _display_name = _('choice')
+ _type = _('choice')
def __init__(self,
name,
@@ -56,7 +57,10 @@ class ChoiceOption(Option):
**kwargs)
def impl_get_values(self,
- option_bag):
+ option_bag: OptionBag,
+ ):
+ """get values allowed by option
+ """
if isinstance(self._choice_values, Calculation):
values = self._choice_values.execute(option_bag)
if values is not undefined and not isinstance(values, list):
@@ -67,20 +71,18 @@ class ChoiceOption(Option):
return values
def validate(self,
- value: Any) -> None:
- pass
-
- 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)
+ value: Any,
+ ) -> None:
+ """nothing to valide
+ """
def validate_with_option(self,
- value: Any,
- option_bag: OptionBag) -> None:
+ value: Any,
+ option_bag: OptionBag,
+ loaded: bool,
+ ) -> None:
+ if loaded and isinstance(self._choice_values, Calculation):
+ return
values = self.impl_get_values(option_bag)
self.validate_values(value, values)
@@ -88,6 +90,8 @@ class ChoiceOption(Option):
value,
values,
) -> None:
+ """validate values
+ """
if values is not undefined and value not in values:
if len(values) == 1:
raise ValueError(_('only "{0}" is allowed'
diff --git a/tiramisu/option/dateoption.py b/tiramisu/option/dateoption.py
index 341b4a2..baf836d 100644
--- a/tiramisu/option/dateoption.py
+++ b/tiramisu/option/dateoption.py
@@ -18,22 +18,24 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
+"""DateOption
+"""
from datetime import datetime
-from ..setting import undefined, Undefined, OptionBag
from ..i18n import _
from .stroption import StrOption
class DateOption(StrOption):
+ """represents the choice of a date
+ """
__slots__ = tuple()
- _type = 'date'
- _display_name = _('date')
+ _type = _('date')
def validate(self,
value: str) -> None:
super().validate(value)
try:
datetime.strptime(value, "%Y-%m-%d")
- except ValueError:
- raise ValueError()
+ except ValueError as err:
+ raise ValueError() from err
diff --git a/tiramisu/option/domainnameoption.py b/tiramisu/option/domainnameoption.py
index fb21ae5..df888b5 100644
--- a/tiramisu/option/domainnameoption.py
+++ b/tiramisu/option/domainnameoption.py
@@ -18,6 +18,8 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
+"""DomainnameOption
+"""
import re
from ipaddress import ip_interface
from typing import Any, Optional, List
@@ -38,8 +40,7 @@ class DomainnameOption(StrOption):
fqdn: with tld, not supported yet
"""
__slots__ = tuple()
- _type = 'domainname'
- _display_name = _('domain name')
+ _type = _('domain name')
def __init__(self,
name: str,
@@ -54,8 +55,9 @@ class DomainnameOption(StrOption):
allow_cidr_network: bool=False,
type: str='domainname',
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']:
raise ValueError(_('unknown type {0} for hostname').format(type))
extra = {'_dom_type': type}
@@ -111,11 +113,10 @@ class DomainnameOption(StrOption):
warnings_only=warnings_only,
extra=extra)
- def _get_len(self, type):
- if type == 'netbios':
+ def _get_len(self, type_):
+ if type_ == 'netbios':
return 15
- else:
- return 63
+ return 63
def _validate_domain(self,
value: str) -> None:
diff --git a/tiramisu/option/dynoptiondescription.py b/tiramisu/option/dynoptiondescription.py
index e2098d8..e71e5e0 100644
--- a/tiramisu/option/dynoptiondescription.py
+++ b/tiramisu/option/dynoptiondescription.py
@@ -18,9 +18,11 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
+"""DynOptionDescription
+"""
import re
import weakref
-from typing import List, Callable, Any
+from typing import List, Any
from itertools import chain
from ..autolib import ParamOption
@@ -28,7 +30,7 @@ from ..autolib import ParamOption
from ..i18n import _
from .optiondescription import OptionDescription
from .baseoption import BaseOption
-from ..setting import OptionBag, ConfigBag, groups, undefined
+from ..setting import OptionBag, ConfigBag
from ..error import ConfigError
from ..autolib import Calculation
@@ -37,6 +39,8 @@ NAME_REGEXP = re.compile(r'^[a-zA-Z\d\-_]*$')
class DynOptionDescription(OptionDescription):
+ """dyn option description
+ """
__slots__ = ('_suffixes',)
def __init__(self,
@@ -46,7 +50,7 @@ class DynOptionDescription(OptionDescription):
suffixes: Calculation,
properties=None,
) -> None:
-
+ # pylint: disable=too-many-arguments
super().__init__(name,
doc,
children,
@@ -69,6 +73,8 @@ class DynOptionDescription(OptionDescription):
def convert_suffix_to_path(self,
suffix: Any,
) -> str:
+ """convert suffix to use it to a path
+ """
if suffix is None:
return None
if not isinstance(suffix, str):
@@ -78,7 +84,10 @@ class DynOptionDescription(OptionDescription):
return suffix
def get_suffixes(self,
- config_bag: ConfigBag) -> List[str]:
+ config_bag: ConfigBag,
+ ) -> List[str]:
+ """get dynamic suffixes
+ """
option_bag = OptionBag(self,
None,
config_bag,
@@ -90,8 +99,9 @@ class DynOptionDescription(OptionDescription):
values_ = []
if __debug__:
if not isinstance(values, list):
- raise ValueError(_('DynOptionDescription suffixes for option "{}", is not a list ({})'
- '').format(self.impl_get_display_name(), values))
+ raise ValueError(_('DynOptionDescription suffixes for '
+ f'option "{self.impl_get_display_name()}", is not '
+ f'a list ({values})'))
for val in values:
cval = self.convert_suffix_to_path(val)
if not isinstance(cval, str) or re.match(NAME_REGEXP, cval) is None:
@@ -106,8 +116,8 @@ class DynOptionDescription(OptionDescription):
extra_values = values_.copy()
for val in set(values_):
extra_values.remove(val)
- raise ValueError(_('DynOptionDescription suffixes return a list with multiple value '
- '"{}"''').format(extra_values))
+ raise ValueError(_('DynOptionDescription suffixes return a list with '
+ f'multiple value "{extra_values}"'''))
return values_
def impl_is_dynoptiondescription(self) -> bool:
diff --git a/tiramisu/option/emailoption.py b/tiramisu/option/emailoption.py
index a0ec7df..95684eb 100644
--- a/tiramisu/option/emailoption.py
+++ b/tiramisu/option/emailoption.py
@@ -18,6 +18,8 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
+"""EmailOption
+"""
import re
from ..i18n import _
@@ -25,7 +27,8 @@ from .stroption import RegexpOption
class EmailOption(RegexpOption):
+ """represents a choice of an email
+ """
__slots__ = tuple()
_regexp = re.compile(r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$")
- _type = 'email'
- _display_name = _('email address')
+ _type = _('email address')
diff --git a/tiramisu/option/filenameoption.py b/tiramisu/option/filenameoption.py
index c13b4de..c5eb090 100644
--- a/tiramisu/option/filenameoption.py
+++ b/tiramisu/option/filenameoption.py
@@ -18,16 +18,17 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
-import re
-
+"""FilenameOption
+"""
from ..i18n import _
from .stroption import StrOption
class FilenameOption(StrOption):
+ """represents a choice of a file name
+ """
__slots__ = tuple()
- _type = 'filename'
- _display_name = _('file name')
+ _type = _('file name')
def validate(self,
value: str,
diff --git a/tiramisu/option/floatoption.py b/tiramisu/option/floatoption.py
index 9944e50..285fa81 100644
--- a/tiramisu/option/floatoption.py
+++ b/tiramisu/option/floatoption.py
@@ -18,17 +18,18 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
+"""FloatOption
+"""
-from ..setting import undefined, Undefined, OptionBag
from ..i18n import _
from .option import Option
class FloatOption(Option):
- "represents a choice of a floating point number"
+ """represents a choice of a floating point number
+ """
__slots__ = tuple()
- _type = 'float'
- _display_name = _('float')
+ _type = _('float')
def validate(self,
value: float) -> None:
diff --git a/tiramisu/option/intoption.py b/tiramisu/option/intoption.py
index 154e61c..a7a6e4e 100644
--- a/tiramisu/option/intoption.py
+++ b/tiramisu/option/intoption.py
@@ -18,8 +18,9 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
+"""IntOption
+"""
-from ..setting import undefined, Undefined, OptionBag
from ..i18n import _
from .option import Option
@@ -27,8 +28,7 @@ from .option import Option
class IntOption(Option):
"represents a choice of an integer"
__slots__ = tuple()
- _type = 'integer'
- _display_name = _('integer')
+ _type = _('integer')
def __init__(self,
*args,
@@ -43,7 +43,8 @@ class IntOption(Option):
super().__init__(*args, extra=extra, **kwargs)
def validate(self,
- value: int) -> None:
+ value: int,
+ ) -> None:
if not isinstance(value, int):
raise ValueError()
diff --git a/tiramisu/option/ipoption.py b/tiramisu/option/ipoption.py
index f3e8d71..c548159 100644
--- a/tiramisu/option/ipoption.py
+++ b/tiramisu/option/ipoption.py
@@ -18,21 +18,19 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
+"""IPOption
+"""
from ipaddress import ip_address, ip_interface
-from ..error import ConfigError
-from ..setting import undefined, Undefined, OptionBag
from ..i18n import _
-from .option import Option
from .stroption import StrOption
-from ..function import valid_ip_netmask
class IPOption(StrOption):
- "represents the choice of an ip"
+ """represents the choice of an ip
+ """
__slots__ = tuple()
- _type = 'ip'
- _display_name = _('IP')
+ _type = _('IP')
def __init__(self,
*args,
@@ -52,19 +50,19 @@ class IPOption(StrOption):
def _validate_cidr(self, value):
try:
- ip = ip_interface(value)
- except ValueError:
- raise ValueError()
- if ip.ip == ip.network.network_address:
+ ip_obj = ip_interface(value)
+ except ValueError as err:
+ raise ValueError() from err
+ if ip_obj.ip == ip_obj.network.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"))
def _validate_ip(self, value):
try:
- new_value = str(ip_address(value))
- except ValueError:
- raise ValueError()
+ str(ip_address(value))
+ except ValueError as err:
+ raise ValueError() from err
def validate(self,
value: str) -> None:
@@ -79,14 +77,14 @@ class IPOption(StrOption):
def second_level_validation(self,
value: str,
warnings_only: bool) -> None:
- ip = ip_interface(value)
- if not self.impl_get_extra('_allow_reserved') and ip.is_reserved:
+ ip_obj = ip_interface(value)
+ if not self.impl_get_extra('_allow_reserved') and ip_obj.is_reserved:
if warnings_only:
msg = _("shouldn't be reserved IP")
else:
msg = _("mustn't be reserved IP")
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:
msg = _("should be private IP")
else:
diff --git a/tiramisu/option/leadership.py b/tiramisu/option/leadership.py
index 0364985..fb1157b 100644
--- a/tiramisu/option/leadership.py
+++ b/tiramisu/option/leadership.py
@@ -20,22 +20,23 @@
# the whole pypy projet is under MIT licence
# ____________________________________________________________
import weakref
-from itertools import chain
-from typing import List, Iterator, Optional, Any
+from typing import List, Iterator, Optional
from ..i18n import _
-from ..setting import groups, undefined, OptionBag, Settings, ALLOWED_LEADER_PROPERTIES
-from ..value import Values
+from ..setting import groups, undefined, OptionBag, ALLOWED_LEADER_PROPERTIES
from .optiondescription import OptionDescription
from .syndynoptiondescription import SynDynLeadership
from .baseoption import BaseOption
from .option import Option
from ..error import LeadershipError
-from ..autolib import Calculation, ParamOption
+from ..autolib import Calculation
class Leadership(OptionDescription):
+ """Leadership
+ """
+ # pylint: disable=too-many-arguments
__slots__ = ('leader',
'followers',
)
@@ -57,35 +58,10 @@ class Leadership(OptionDescription):
leader = children[0]
for idx, child in enumerate(children):
if __debug__:
- 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()))
- 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()))
+ self._check_child_is_valid(child)
if idx != 0:
+ if __debug__:
+ self._check_default_value(child)
# remove empty property for follower
child._properties = frozenset(child._properties - {'empty', 'unique'})
followers.append(child)
@@ -96,35 +72,78 @@ class Leadership(OptionDescription):
if prop not in ALLOWED_LEADER_PROPERTIES and not isinstance(prop, Calculation):
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,
subdyn,
) -> None:
+ # pylint: disable=attribute-defined-outside-init,protected-access
for chld in self._children[1]:
chld._setsubdyn(subdyn)
self._subdyn = subdyn
def is_leader(self,
- opt: Option) -> bool:
+ opt: Option,
+ ) -> bool:
+ """the option is the leader
+ """
leader = self.get_leader()
return opt == leader or (opt.impl_is_dynsymlinkoption() and opt.opt == leader)
def get_leader(self) -> Option:
+ """get leader
+ """
return self._children[1][0]
def get_followers(self) -> Iterator[Option]:
+ """get all followers
+ """
for follower in self._children[1][1:]:
yield follower
- def in_same_group(self,
- opt: Option) -> bool:
+ def in_same_leadership(self,
+ opt: Option,
+ ) -> bool:
+ """check if followers are in same leadership
+ """
if opt.impl_is_dynsymlinkoption():
opt = opt.opt
return opt in self._children[1]
- def reset(self,
- values: Values,
- option_bag: OptionBag) -> None:
- config_bag = option_bag.config_bag.copy()
+ def reset(self, config_bag: 'ConfigBag') -> None:
+ """reset follower value
+ """
+ values = config_bag.context.get_values()
+ config_bag = config_bag.copy()
config_bag.remove_validation()
for follower in self.get_followers():
soption_bag = OptionBag(follower,
@@ -134,71 +153,60 @@ class Leadership(OptionDescription):
values.reset(soption_bag)
def follower_force_store_value(self,
- values,
- value,
- option_bag,
- owner,
- dyn=None,
- ) -> None:
- settings = option_bag.config_bag.context.get_settings()
+ value,
+ config_bag: 'ConfigBag',
+ owner,
+ dyn=None,
+ ) -> None:
+ """apply force_store_value to follower
+ """
if value:
if dyn is None:
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,
None,
- option_bag.config_bag,
+ config_bag,
)
- if 'force_store_value' in foption_bag.properties:
- if idx == 0:
- indexes = [None]
- else:
- indexes = range(len(value))
- for index in indexes:
- foption_bag_index = OptionBag(follower,
- index,
- option_bag.config_bag,
- )
- values.set_storage_value(foption_bag_index.path,
- index,
- values.getvalue(foption_bag_index),
- owner,
- )
+ if 'force_store_value' not in foption_bag.properties:
+ continue
+ if idx == 0:
+ indexes = [None]
+ else:
+ indexes = range(len(value))
+ for index in indexes:
+ foption_bag_index = OptionBag(follower,
+ index,
+ config_bag,
+ )
+ values.set_storage_value(foption_bag_index.path,
+ index,
+ values.get_value(foption_bag_index),
+ owner,
+ )
def pop(self,
- values: Values,
index: int,
- option_bag: OptionBag,
+ config_bag: 'ConfigBag',
followers: Optional[List[Option]]=undefined,
) -> None:
+ """pop leader value and follower's one
+ """
if followers is undefined:
# followers are not undefined only in SynDynLeadership
followers = self.get_followers()
- config_bag = option_bag.config_bag.copy()
+ config_bag = config_bag.copy()
config_bag.remove_validation()
+ values = config_bag.context.get_values()
for follower in followers:
- follower_path = follower.impl_getpath()
- followerlen = values.get_max_length(follower_path)
soption_bag = OptionBag(follower,
index,
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,
- 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,
- )
+ values.reduce_index(soption_bag)
def reset_cache(self,
path: str,
@@ -221,17 +229,16 @@ class Leadership(OptionDescription):
) -> None:
super().reset_cache(path,
config_bag,
- resetted_opts)
+ resetted_opts,
+ )
leader.reset_cache(leader.impl_getpath(),
config_bag,
None)
for follower in followers:
- spath = follower.impl_getpath()
- follower.reset_cache(spath,
+ follower.reset_cache(follower.impl_getpath(),
config_bag,
- None)
- # do not reset dependencies option
- # resetted_opts.append(spath)
+ None,
+ )
def impl_is_leadership(self) -> None:
return True
diff --git a/tiramisu/option/macoption.py b/tiramisu/option/macoption.py
index d5097a3..57dbd8a 100644
--- a/tiramisu/option/macoption.py
+++ b/tiramisu/option/macoption.py
@@ -18,6 +18,8 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
+"""MACOption
+"""
import re
from ..i18n import _
@@ -25,7 +27,8 @@ from .stroption import RegexpOption
class MACOption(RegexpOption):
+ """represents the choice of a mac address
+ """
__slots__ = tuple()
_regexp = re.compile(r"^([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})$")
- _type = 'macaddress'
- _display_name = _('mac address')
+ _type = _('mac address')
diff --git a/tiramisu/option/netmaskoption.py b/tiramisu/option/netmaskoption.py
index 47e893c..43785b1 100644
--- a/tiramisu/option/netmaskoption.py
+++ b/tiramisu/option/netmaskoption.py
@@ -18,21 +18,18 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
-from ipaddress import ip_interface, ip_network
-from typing import List
-
-from ..error import ConfigError
-from ..setting import undefined, OptionBag, Undefined
+"""NetmaskOption
+"""
+from ipaddress import ip_network
from ..i18n import _
-from .option import Option
from .stroption import StrOption
class NetmaskOption(StrOption):
- "represents the choice of a netmask"
+ """represents the choice of a netmask
+ """
__slots__ = tuple()
- _type = 'netmask'
- _display_name = _('netmask address')
+ _type = _('netmask address')
def validate(self,
value: str) -> None:
@@ -41,6 +38,6 @@ class NetmaskOption(StrOption):
if val.startswith("0") and len(val) > 1:
raise ValueError()
try:
- ip_network('0.0.0.0/{0}'.format(value))
- except ValueError:
- raise ValueError()
+ ip_network(f'0.0.0.0/{value}')
+ except ValueError as err:
+ raise ValueError() from err
diff --git a/tiramisu/option/networkoption.py b/tiramisu/option/networkoption.py
index caf85c3..4787799 100644
--- a/tiramisu/option/networkoption.py
+++ b/tiramisu/option/networkoption.py
@@ -18,7 +18,9 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# 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 .stroption import StrOption
@@ -27,8 +29,7 @@ from .stroption import StrOption
class NetworkOption(StrOption):
"represents the choice of a network"
__slots__ = tuple()
- _type = 'network'
- _display_name = _('network address')
+ _type = _('network address')
def __init__(self,
*args,
@@ -56,8 +57,8 @@ class NetworkOption(StrOption):
raise ValueError()
try:
ip_network(value)
- except ValueError:
- raise ValueError()
+ except ValueError as err:
+ raise ValueError() from err
def second_level_validation(self,
value: str,
diff --git a/tiramisu/option/option.py b/tiramisu/option/option.py
index e9c8008..ba2b998 100644
--- a/tiramisu/option/option.py
+++ b/tiramisu/option/option.py
@@ -20,21 +20,19 @@
# the whole pypy projet is under MIT licence
# ____________________________________________________________
import warnings
-import weakref
-from typing import Any, List, Callable, Optional, Dict, Union, Tuple
+from typing import Any, List, Optional, Dict
from itertools import chain
-from .baseoption import BaseOption, submulti, STATIC_TUPLE
+from .baseoption import BaseOption, submulti
from ..i18n import _
-from ..setting import undefined, OptionBag, Undefined
-from ..autolib import Calculation, Params, ParamOption, ParamInformation, ParamSelfInformation
-from ..error import (ConfigError, ValueWarning, ValueErrorWarning,
- ValueOptionError, display_list)
+from ..setting import undefined, OptionBag
+from ..autolib import Calculation, ParamOption, ParamInformation, ParamSelfInformation
+from ..error import ValueWarning, ValueErrorWarning, ValueOptionError
from .syndynoption import SynDynOption
-#ALLOWED_CONST_LIST = ['_cons_not_equal']
class Option(BaseOption):
+ # pylint: disable=too-many-statements,too-many-branches,too-many-arguments,too-many-locals
"""
Abstract base class for configuration option's.
@@ -55,7 +53,7 @@ class Option(BaseOption):
'_choice_values',
'_choice_values_params',
)
- _empty = ''
+ _type = None
def __init__(self,
name: str,
doc: str,
@@ -99,7 +97,7 @@ class Option(BaseOption):
is_multi=is_multi)
if validators is not None:
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:
if __debug__ and not isinstance(validator, Calculation):
raise ValueError(_('validators must be a Calculation for "{}"').format(name))
@@ -128,19 +126,20 @@ class Option(BaseOption):
)
try:
self.validate(value)
- self.sync_validate_with_option(value,
- option_bag)
+ self.validate_with_option(value,
+ option_bag,
+ loaded=True,
+ )
except ValueError as err:
str_err = str(err)
if not str_err:
raise ValueError(_('invalid default_multi value "{0}" '
'for option "{1}"').format(str(value),
- self.impl_get_display_name()))
- else:
- raise ValueError(_('invalid default_multi value "{0}" '
- 'for option "{1}", {2}').format(str(value),
- self.impl_get_display_name(),
- str_err))
+ self.impl_get_display_name())
+ ) from err
+ raise ValueError(_(f'invalid default_multi value "{value}" for option '
+ f'"{self.impl_get_display_name()}", {str_err}')
+ ) from err
if _multi is submulti:
if not isinstance(default_multi, Calculation):
if not isinstance(default_multi, list):
@@ -158,11 +157,15 @@ class Option(BaseOption):
undefined,
properties=None,
)
- self.sync_impl_validate(default,
- option_bag)
- self.sync_impl_validate(default,
- option_bag,
- check_error=False)
+ self.impl_validate(default,
+ option_bag,
+ loaded=True,
+ )
+ self.impl_validate(default,
+ option_bag,
+ check_error=False,
+ loaded=True,
+ )
self.value_dependencies(default, _dependencies_information)
if (is_multi and default != []) or \
(not is_multi and default is not None):
@@ -176,6 +179,8 @@ class Option(BaseOption):
value: Any,
_dependencies_information: List[str],
) -> Any:
+ """parse dependancies to add dependencies
+ """
if isinstance(value, list):
for val in value:
if isinstance(value, list):
@@ -189,8 +194,11 @@ class Option(BaseOption):
value: Any,
_dependencies_information: List[str],
) -> Any:
+ """parse dependancy to add dependencies
+ """
for param in chain(value.params.args, value.params.kwargs.values()):
if isinstance(param, ParamOption):
+ # pylint: disable=protected-access
param.option._add_dependency(self)
elif isinstance(param, ParamSelfInformation):
_dependencies_information[1].append(param.information_name)
@@ -201,23 +209,28 @@ class Option(BaseOption):
# option's information
def impl_is_multi(self) -> bool:
+ """is it a multi option
+ """
return getattr(self, '_multi', 1) != 1
def impl_is_submulti(self) -> bool:
+ """is it a submulti option
+ """
return getattr(self, '_multi', 1) == 2
def impl_is_dynsymlinkoption(self) -> bool:
+ """is a dynsymlinkoption?
+ """
return False
def get_type(self) -> str:
- # _display_name for compatibility with older version than 3.0rc3
- return getattr(self, '_type', self._display_name)
-
- def get_display_type(self) -> str:
- return self._display_name
+ """get the type of option
+ """
+ return self._type
def impl_getdefault(self) -> Any:
- "accessing the default value"
+ """accessing the default value
+ """
is_multi = self.impl_is_multi()
default = getattr(self, '_default', undefined)
if default is undefined:
@@ -225,13 +238,13 @@ class Option(BaseOption):
default = []
else:
default = None
- else:
- if is_multi and isinstance(default, list):
- default = list(default)
+ elif is_multi and isinstance(default, tuple):
+ default = list(default)
return default
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():
default_value = []
else:
@@ -239,93 +252,25 @@ class Option(BaseOption):
return getattr(self, '_default_multi', default_value)
def impl_get_extra(self,
- key: str) -> Any:
+ key: str,
+ ) -> Any:
+ """if extra parameters are store get it
+ """
extra = getattr(self, '_extra', {})
if isinstance(extra, tuple):
if key in extra[0]:
return extra[1][extra[0].index(key)]
return None
- else:
- return extra.get(key)
+ return extra.get(key)
#__________________________________________________________________________
# 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,
- value: Any,
- option_bag: OptionBag,
- check_error: bool=True) -> None:
+ value: Any,
+ option_bag: OptionBag,
+ check_error: bool=True,
+ loaded: bool=False,
+ ) -> None:
"""Return True if value is really valid
If not validate or invalid return it returns False
"""
@@ -337,7 +282,6 @@ class Option(BaseOption):
not 'validator' in config_bag.properties:
return False
-
def _is_not_unique(value, option_bag):
# if set(value) has not same length than value
if config_bag is undefined or not check_error or \
@@ -353,9 +297,11 @@ class Option(BaseOption):
'').format(val))
def calculation_validator(val,
- _index):
+ _index,
+ ):
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
(not check_error and calc_is_warnings_only)):
try:
@@ -374,26 +320,32 @@ class Option(BaseOption):
**kwargs)
except ValueWarning as warn:
warnings.warn_explicit(ValueWarning(val,
- self._display_name,
+ self.get_type(),
self,
- '{0}'.format(warn),
+ str(warn),
_index),
ValueWarning,
- self.__class__.__name__, 356)
+ self.__class__.__name__, 319)
def do_validation(_value,
- _index):
+ _index,
+ ):
+ #
if isinstance(_value, list):
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:
- return False
+ return
+
if _value is not None:
if check_error:
# option validation
self.validate(_value)
self.validate_with_option(_value,
- option_bag)
+ option_bag,
+ loaded=loaded,
+ )
if ((check_error and not is_warnings_only) or
(not check_error and is_warnings_only)):
try:
@@ -402,16 +354,18 @@ class Option(BaseOption):
except ValueError as err:
if is_warnings_only:
warnings.warn_explicit(ValueWarning(_value,
- self._display_name,
+ self.get_type(),
self,
- '{0}'.format(err),
+ str(err),
_index),
ValueWarning,
self.__class__.__name__, 0)
else:
raise err
- calculation_validator(_value,
- _index)
+ if not loaded:
+ calculation_validator(_value,
+ _index,
+ )
try:
val = value
err_index = force_index
@@ -423,11 +377,15 @@ class Option(BaseOption):
raise ValueError(_('which must be a list'))
for val in value:
do_validation(val,
- force_index)
- _is_not_unique(value, option_bag)
+ force_index,
+ )
+ _is_not_unique(value,
+ option_bag,
+ )
else:
do_validation(val,
- force_index)
+ force_index,
+ )
elif isinstance(value, Calculation) and config_bag is undefined:
pass
elif not isinstance(value, list):
@@ -444,73 +402,68 @@ class Option(BaseOption):
err_index)
_is_not_unique(lval, option_bag)
else:
- # FIXME subtimal, not several time is whole=True!
+ # FIXME suboptimal, not several time is whole=True!
for err_index, val in enumerate(value):
do_validation(val,
- err_index)
+ err_index,
+ )
_is_not_unique(value, option_bag)
except ValueError as err:
if config_bag is undefined or \
'demoting_error_warning' not in config_bag.properties:
raise ValueOptionError(val,
- self._display_name,
+ self.get_type(),
option_bag.ori_option,
- '{0}'.format(err),
+ str(err),
err_index) from err
warnings.warn_explicit(ValueErrorWarning(val,
- self._display_name,
+ self.get_type(),
option_bag.ori_option,
- '{0}'.format(err),
+ str(err),
err_index),
ValueErrorWarning,
self.__class__.__name__, 0)
return False
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,
value: Any,
- option_bag: OptionBag) -> None:
- pass
+ option_bag: OptionBag,
+ loaded: bool,
+ ) -> None:
+ """validation function with option
+ """
def second_level_validation(self,
value: Any,
- warnings_only: bool) -> None:
- pass
+ warnings_only: bool,
+ ) -> None:
+ """less import validation function
+ """
def impl_is_leader(self):
+ """check if option is a leader in a leadership
+ """
leadership = self.impl_get_leadership()
if leadership is None:
return False
return leadership.is_leader(self)
def impl_is_follower(self):
+ """check if option is a leader in a follower
+ """
leadership = self.impl_get_leadership()
if leadership is None:
return False
return not leadership.is_leader(self)
def impl_get_leadership(self):
+ """get leadership
+ """
leadership = getattr(self, '_leadership', None)
if leadership is None:
return leadership
+ #pylint: disable=not-callable
return leadership()
def to_dynoption(self,
@@ -518,8 +471,14 @@ class Option(BaseOption):
suffix: str,
dyn_parent,
) -> SynDynOption:
+ """tranforme a dynoption to a syndynoption
+ """
return SynDynOption(self,
rootpath,
suffix,
dyn_parent,
)
+ def validate(self, value: Any):
+ """option needs a validate function
+ """
+ raise NotImplementedError()
diff --git a/tiramisu/option/optiondescription.py b/tiramisu/option/optiondescription.py
index 17d3798..d6f18ee 100644
--- a/tiramisu/option/optiondescription.py
+++ b/tiramisu/option/optiondescription.py
@@ -18,27 +18,31 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
-from copy import copy
+"""OptionDescription
+"""
from typing import Optional, Iterator, Union, List
from ..i18n import _
from ..setting import ConfigBag, OptionBag, groups, undefined, owners, Undefined
from .baseoption import BaseOption
-from .syndynoptiondescription import SynDynOptionDescription, SynDynLeadership
+from .syndynoptiondescription import SynDynOptionDescription
from ..error import ConfigError, ConflictError
class CacheOptionDescription(BaseOption):
+ """manage cache for option description
+ """
__slots__ = ('_cache_force_store_values',
'_cache_dependencies_information',
)
def impl_already_build_caches(self) -> bool:
+ """is a readonly option?
+ """
return self.impl_is_readonly()
def _build_cache(self,
- path='',
_consistencies=None,
_consistencies_id=0,
currpath: List[str]=None,
@@ -49,6 +53,7 @@ class CacheOptionDescription(BaseOption):
) -> None:
"""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
if _consistencies is None:
init = True
@@ -65,15 +70,16 @@ class CacheOptionDescription(BaseOption):
# cache already set
raise ConfigError(_('option description seems to be part of an other '
'config'))
- for option in self.get_children(config_bag=undefined,
- dyn=False):
+ for option in self.get_children(config_bag=undefined, # pylint: disable=no-member
+ dyn=False,
+ ):
if __debug__:
cache_option.append(option)
sub_currpath = currpath + [option.impl_getname()]
subpath = '.'.join(sub_currpath)
if isinstance(option, OptionDescription):
- option._build_cache(subpath,
- _consistencies,
+ # pylint: disable=protected-access
+ option._build_cache(_consistencies,
_consistencies_id,
sub_currpath,
cache_option,
@@ -84,7 +90,6 @@ class CacheOptionDescription(BaseOption):
else:
for information in option.get_dependencies_information():
dependencies_information.setdefault(information, []).append(option)
- is_multi = option.impl_is_multi()
if not option.impl_is_symlinkoption():
properties = option.impl_getproperties()
if 'force_store_value' in properties:
@@ -101,18 +106,21 @@ class CacheOptionDescription(BaseOption):
if option.impl_is_readonly():
raise ConflictError(_('duplicate option: {0}').format(option))
if not self.impl_is_readonly() and display_name:
- option._display_name_function = display_name
- option._path = subpath
- option._set_readonly()
+ option._display_name_function = display_name # pylint: disable=protected-access
+ option._path = subpath # pylint: disable=protected-access
+ option._set_readonly() # pylint: disable=protected-access
if init:
- self._cache_force_store_values = force_store_values
- self._cache_dependencies_information = dependencies_information
- self._path = self._name
+ self._cache_force_store_values = force_store_values # pylint: disable=attribute-defined-outside-init
+ self._cache_dependencies_information = dependencies_information # pylint: disable=attribute-defined-outside-init
+ self._path = self._name # pylint: disable=attribute-defined-outside-init,no-member
self._set_readonly()
def impl_build_force_store_values(self,
config_bag: ConfigBag,
) -> None:
+ """set value to force_store_values option
+ """
+ # pylint: disable=too-many-branches
def do_option_bags(option):
if option.issubdyn():
dynopt = option.getsubdyn()
@@ -146,7 +154,7 @@ class CacheOptionDescription(BaseOption):
leader = option.impl_get_leadership().get_leader()
for leader_option_bag in do_option_bags(leader):
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():
subpath = leader_option_bag.option.rootpath
doption = option.to_dynoption(subpath,
@@ -164,7 +172,7 @@ class CacheOptionDescription(BaseOption):
config_bag,
properties=frozenset(),
)
- value = values.getvalue(option_bag)
+ value = values.get_value(option_bag)
if value is None:
continue
values.set_storage_value(subpath,
@@ -175,7 +183,7 @@ class CacheOptionDescription(BaseOption):
else:
for option_bag in do_option_bags(option):
option_bag.properties = frozenset()
- value = values.getvalue(option_bag)
+ value = values.get_value(option_bag)
if value is None:
continue
if values.hasvalue(option_bag.option.impl_getpath()):
@@ -188,6 +196,8 @@ class CacheOptionDescription(BaseOption):
class OptionDescriptionWalk(CacheOptionDescription):
+ """get child of option description
+ """
__slots__ = ('_children',)
def get_child(self,
@@ -195,16 +205,18 @@ class OptionDescriptionWalk(CacheOptionDescription):
config_bag: ConfigBag,
subpath: str,
) -> Union[BaseOption, SynDynOptionDescription]:
+ """get a child
+ """
# if not dyn
- if name in self._children[0]:
- option = self._children[1][self._children[0].index(name)]
+ if name in self._children[0]: # pylint: disable=no-member
+ option = self._children[1][self._children[0].index(name)] # pylint: disable=no-member
if option.issubdyn():
raise AttributeError(_(f'unknown option "{name}" '
"in root optiondescription (it's a dynamic option)"
))
return option
# if dyn
- for child in self._children[1]:
+ for child in self._children[1]: # pylint: disable=no-member
if not child.impl_is_dynoptiondescription():
continue
cname = child.impl_getname()
@@ -217,7 +229,7 @@ class OptionDescriptionWalk(CacheOptionDescription):
suffix,
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}" '
'in root optiondescription'
))
@@ -229,21 +241,22 @@ class OptionDescriptionWalk(CacheOptionDescription):
config_bag: Union[ConfigBag, Undefined],
dyn: bool=True,
) -> Union[BaseOption, SynDynOptionDescription]:
+ """get children
+ """
if not dyn or config_bag is undefined or \
config_bag.context.get_description() == self:
subpath = ''
else:
subpath = self.impl_getpath()
- children = []
- for child in self._children[1]:
+ for child in self._children[1]: # pylint: disable=no-member
if dyn and child.impl_is_dynoptiondescription():
for suffix in child.get_suffixes(config_bag):
- children.append(child.to_dynoption(subpath,
- suffix,
- child))
+ yield child.to_dynoption(subpath,
+ suffix,
+ child,
+ )
else:
- children.append(child)
- return children
+ yield child
def get_children_recursively(self,
bytype: Optional[BaseOption],
@@ -251,6 +264,8 @@ class OptionDescriptionWalk(CacheOptionDescription):
config_bag: ConfigBag,
self_opt: BaseOption=None,
) -> Iterator[Union[BaseOption, SynDynOptionDescription]]:
+ """get children recursively
+ """
if self_opt is None:
self_opt = self
for option in self_opt.get_children(config_bag):
@@ -308,8 +323,8 @@ class OptionDescription(OptionDescriptionWalk):
if dynopt_names:
for dynopt in dynopt_names:
if child != dynopt and child.startswith(dynopt):
- raise ConflictError(_('the option\'s name "{}" start as '
- 'the dynoptiondescription\'s name "{}"').format(child, dynopt))
+ raise ConflictError(_(f'the option\'s name "{child}" start as '
+ f'the dynoptiondescription\'s name "{dynopt}"'))
old = child
self._children = children_
# the group_type is useful for filtering OptionDescriptions in a config
@@ -322,17 +337,24 @@ class OptionDescription(OptionDescriptionWalk):
'dynoptiondescription'))
def impl_is_optiondescription(self) -> bool:
+ """the option is an option description
+ """
return True
def impl_is_dynoptiondescription(self) -> bool:
+ """the option is not dynamic
+ """
return False
def impl_is_leadership(self) -> bool:
+ """the option is not a leadership
+ """
return False
# ____________________________________________________________
def impl_set_group_type(self,
- group_type: groups.GroupType) -> None:
+ group_type: groups.GroupType,
+ ) -> None:
"""sets a given group object to an OptionDescription
:param group_type: an instance of `GroupType` or `LeadershipGroupType`
@@ -351,16 +373,22 @@ class OptionDescription(OptionDescriptionWalk):
self._group_type = group_type
def impl_get_group_type(self) -> groups.GroupType:
+ """get the group type of option description
+ """
return self._group_type
def to_dynoption(self,
rootpath: str,
suffix: str,
ori_dyn) -> SynDynOptionDescription:
+ """get syn dyn option description
+ """
return SynDynOptionDescription(self,
rootpath,
suffix,
ori_dyn)
def impl_is_dynsymlinkoption(self) -> bool:
+ """option is not a dyn symlink option
+ """
return False
diff --git a/tiramisu/option/passwordoption.py b/tiramisu/option/passwordoption.py
index 042c66b..05fdf2a 100644
--- a/tiramisu/option/passwordoption.py
+++ b/tiramisu/option/passwordoption.py
@@ -18,15 +18,15 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
+"""PasswordOption
+"""
-from ..setting import undefined, Undefined, OptionBag
from ..i18n import _
-from .option import Option
from .stroption import StrOption
class PasswordOption(StrOption):
- "represents the choice of a password"
+ """represents the choice of a password
+ """
__slots__ = tuple()
- _type = 'password'
- _display_name = _('password')
+ _type = _('password')
diff --git a/tiramisu/option/permissionsoption.py b/tiramisu/option/permissionsoption.py
index 5d07ae3..b156786 100644
--- a/tiramisu/option/permissionsoption.py
+++ b/tiramisu/option/permissionsoption.py
@@ -18,12 +18,11 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
+"""PermissionsOption
+"""
import re
-import sys
-from ..setting import undefined, Undefined, OptionBag
from ..i18n import _
-from .option import Option
from .intoption import IntOption
@@ -36,8 +35,7 @@ class PermissionsOption(IntOption):
"""
__slots__ = tuple()
perm_re = re.compile(r"^[0-7]{3,4}$")
- _type = 'permissions'
- _display_name = _('unix file permissions')
+ _type = _('unix file permissions')
def __init__(self,
*args,
@@ -72,4 +70,4 @@ class PermissionsOption(IntOption):
raise ValueError(_(f'{new} has more right than {old}'))
old_digit = new_digit
if str_value == '777':
- raise ValueError(_(f'too weak'))
+ raise ValueError(_('too weak'))
diff --git a/tiramisu/option/portoption.py b/tiramisu/option/portoption.py
index 19752e1..7ca1f71 100644
--- a/tiramisu/option/portoption.py
+++ b/tiramisu/option/portoption.py
@@ -18,6 +18,8 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
+"""PortOption
+"""
import re
from ..i18n import _
@@ -36,8 +38,7 @@ class PortOption(StrOption):
"""
__slots__ = tuple()
port_re = re.compile(r"^[0-9]*$")
- _type = 'port'
- _display_name = _('port')
+ _port = _('port')
def __init__(self,
*args,
@@ -81,7 +82,8 @@ class PortOption(StrOption):
def validate(self,
value: str) -> None:
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:]]
elif self.impl_get_extra('_allow_range') and ":" in str(value):
value = value.split(':')
@@ -100,7 +102,8 @@ class PortOption(StrOption):
def second_level_validation(self,
value: str,
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:]]
elif ':' in value:
value = value.split(':')
diff --git a/tiramisu/option/stroption.py b/tiramisu/option/stroption.py
index 4c92add..785873e 100644
--- a/tiramisu/option/stroption.py
+++ b/tiramisu/option/stroption.py
@@ -18,31 +18,40 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
-import sys
+"""StrOption and RegexpOption
+"""
from typing import Any
-from ..setting import undefined, Undefined, OptionBag
from ..i18n import _
from .option import Option
class StrOption(Option):
- "represents the choice of a string"
+ """represents a string
+ """
__slots__ = tuple()
- _type = 'string'
- _display_name = _('string')
+ _type = _('string')
def validate(self,
- value: str) -> None:
+ value: str,
+ ) -> None:
+ """validation
+ """
if not isinstance(value, str):
raise ValueError()
class RegexpOption(StrOption):
+ """regexp validation, this is base option use to do a custom's one
+ """
__slots__ = tuple()
def validate(self,
- value: Any) -> None:
+ value: Any,
+ ) -> None:
+ # pylint: disable=no-member
+ """validation
+ """
super().validate(value)
match = self._regexp.search(value)
if not match:
diff --git a/tiramisu/option/symlinkoption.py b/tiramisu/option/symlinkoption.py
index b55fe70..3526f6b 100644
--- a/tiramisu/option/symlinkoption.py
+++ b/tiramisu/option/symlinkoption.py
@@ -18,6 +18,8 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
+"""SymLinkOption link to an other option
+"""
from typing import Any
from .baseoption import BaseOption, valid_name
from ..error import ConfigError
@@ -25,11 +27,15 @@ from ..i18n import _
class SymLinkOption(BaseOption):
+ """SymLinkOption link to an other option
+ """
__slots__ = ('_opt',)
def __init__(self,
name: str,
- opt: BaseOption) -> None:
+ opt: BaseOption,
+ ) -> None:
+ # pylint: disable=super-init-not-called
if not valid_name(name):
raise ValueError(_('"{0}" is an invalid name for an option').format(name))
if not isinstance(opt, BaseOption) or \
@@ -55,27 +61,36 @@ class SymLinkOption(BaseOption):
'dynoptiondescription'))
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 False, cannot has validation or callback, so return False
"""
return self_is_dep
def impl_is_symlinkoption(self) -> bool:
+ """it's a symlinkoption
+ """
return True
def impl_getopt(self) -> BaseOption:
+ """get to linked option
+ """
return self._opt
def issubdyn(self) -> bool:
+ """it's not a sub dyn option
+ """
return False
def impl_is_multi(self) -> bool:
+ """is it a multi?
+ """
if self._opt.issubdyn():
return True
return self._opt.impl_is_multi()
def impl_is_submulti(self) -> bool:
- if self._opt.issubdyn() and self._opt.impl_is_multi():
- return True
+ """is it a submulti?
+ """
return self._opt.impl_is_submulti()
diff --git a/tiramisu/option/syndynoption.py b/tiramisu/option/syndynoption.py
index 8f1fbc2..17c616d 100644
--- a/tiramisu/option/syndynoption.py
+++ b/tiramisu/option/syndynoption.py
@@ -18,8 +18,9 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
+"""SynDynOption internal option, it's an instanciate synoption
+"""
from typing import Any
-from ..setting import undefined, OptionBag
from .baseoption import BaseOption
@@ -49,35 +50,40 @@ class SynDynOption:
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:
+ """get option name
+ """
return self.opt.impl_getname() + self.dyn_parent.convert_suffix_to_path(self.suffix)
def impl_get_display_name(self) -> str:
- return self.opt._get_display_name(dyn_name=self.impl_getname(),
- suffix=self.dyn_parent.convert_suffix_to_path(self.suffix),
+ """get option display name
+ """
+ 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:
+ """get suffix
+ """
return self.suffix
def impl_getpath(self) -> str:
+ """get path
+ """
path = self.impl_getname()
if self.rootpath:
path = f'{self.rootpath}.{path}'
return path
def impl_is_dynsymlinkoption(self) -> bool:
+ """it's a dynsymlinkoption
+ """
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()
if leadership:
rootpath = self.rootpath.rsplit('.', 1)[0]
diff --git a/tiramisu/option/syndynoptiondescription.py b/tiramisu/option/syndynoptiondescription.py
index f7cd316..ae2cf50 100644
--- a/tiramisu/option/syndynoptiondescription.py
+++ b/tiramisu/option/syndynoptiondescription.py
@@ -18,17 +18,21 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# 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 ..i18n import _
-from ..setting import ConfigBag, groups, undefined, Settings
-from ..value import Values
+from ..setting import ConfigBag
from .baseoption import BaseOption
from .syndynoption import SynDynOption
class SynDynOptionDescription:
+ """SynDynOptionDescription internal option, it's an instanciate synoptiondescription
+ """
__slots__ = ('opt',
'rootpath',
'_suffix',
@@ -53,14 +57,14 @@ class SynDynOptionDescription:
name,
)
- def impl_getopt(self) -> BaseOption:
- return self.opt
-
def get_child(self,
name: str,
config_bag: ConfigBag,
subpath: str,
) -> BaseOption:
+ """get child by name
+ """
+ # pylint: disable=unused-argument
suffix = self.ori_dyn.convert_suffix_to_path(self._suffix)
if name.endswith(suffix):
oname = name[:-len(suffix)]
@@ -78,15 +82,17 @@ class SynDynOptionDescription:
'').format(name, self.impl_get_display_name()))
def impl_getname(self) -> str:
+ """get name
+ """
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,
config_bag: ConfigBag,
dyn: bool=True,
):
+ # pylint: disable=unused-argument
+ """get children
+ """
subpath = self.impl_getpath()
children = []
for child in self.opt.get_children(config_bag):
@@ -97,6 +103,8 @@ class SynDynOptionDescription:
return children
def impl_is_dynsymlinkoption(self) -> bool:
+ """it's a dynsymlinkoption
+ """
return True
def get_children_recursively(self,
@@ -105,6 +113,9 @@ class SynDynOptionDescription:
config_bag: ConfigBag,
self_opt: BaseOption=None,
) -> BaseOption:
+ # pylint: disable=unused-argument
+ """get children recursively
+ """
for option in self.opt.get_children_recursively(bytype,
byname,
config_bag,
@@ -113,23 +124,33 @@ class SynDynOptionDescription:
yield option
def impl_getpath(self) -> str:
+ """get path
+ """
path = self.impl_getname()
if self.rootpath:
path = f'{self.rootpath}.{path}'
return path
def impl_get_display_name(self) -> str:
+ """get display name
+ """
return self.opt.impl_get_display_name() + str(self._suffix)
class SynDynLeadership(SynDynOptionDescription):
+ """SynDynLeadership internal option, it's an instanciate synoptiondescription
+ """
def get_leader(self) -> SynDynOption:
+ """get the leader
+ """
return self.opt.get_leader().to_dynoption(self.impl_getpath(),
self._suffix,
self.ori_dyn,
)
def get_followers(self) -> Iterator[SynDynOption]:
+ """get followers
+ """
subpath = self.impl_getpath()
for follower in self.opt.get_followers():
yield follower.to_dynoption(subpath,
@@ -142,6 +163,8 @@ class SynDynLeadership(SynDynOptionDescription):
config_bag: 'ConfigBag',
resetted_opts: List[str],
) -> None:
+ """reset cache
+ """
leader = self.get_leader()
followers = self.get_followers()
self._reset_cache(path,
@@ -155,23 +178,27 @@ class SynDynLeadership(SynDynOptionDescription):
*args,
**kwargs,
) -> None:
+ """pop value for a follower
+ """
self.opt.pop(*args,
followers=self.get_followers(),
**kwargs,
)
def follower_force_store_value(self,
- values,
value,
- option_bag,
+ config_bag,
owner,
) -> None:
- self.opt.follower_force_store_value(values,
- value,
- option_bag,
+ """force store value for a follower
+ """
+ self.opt.follower_force_store_value(value,
+ config_bag,
owner,
dyn=self,
)
def impl_getsuffix(self) -> str:
+ """get suffix
+ """
return self._suffix
diff --git a/tiramisu/option/urloption.py b/tiramisu/option/urloption.py
index 8c14bfc..31bbb8f 100644
--- a/tiramisu/option/urloption.py
+++ b/tiramisu/option/urloption.py
@@ -18,22 +18,25 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
+"""URLOption to check url value
+"""
import re
from typing import Any, Optional, List, Dict
-from ..setting import undefined, Undefined, OptionBag
+from ..setting import undefined
from ..i18n import _
-from .option import Option, Calculation
+from .option import Calculation
from .stroption import StrOption
from .domainnameoption import DomainnameOption
from .portoption import PortOption
class URLOption(StrOption):
+ """URLOption to check url value
+ """
__slots__ = tuple()
path_re = re.compile(r"^[A-Za-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$")
- _type = 'url'
- _display_name = _('URL')
+ _type = _('URL')
def __init__(self,
name: str,
@@ -53,8 +56,7 @@ class URLOption(StrOption):
allow_wellknown: bool=True,
allow_registred: bool=True,
allow_private: bool=False) -> None:
-
-
+ # pylint: disable=too-many-arguments,too-many-locals,redefined-builtin
extra = {'_domainname': DomainnameOption(name,
doc,
allow_ip=allow_ip,
@@ -80,10 +82,10 @@ class URLOption(StrOption):
def _get_domain_port_files(self,
value: str) -> (str, str):
if value.startswith('http://'):
- type = 'http'
+ type_ = 'http'
value = value[7:]
elif value.startswith('https://'):
- type = 'https'
+ type_ = 'https'
value = value[8:]
else:
raise ValueError(_('must start with http:// or '
@@ -100,7 +102,7 @@ class URLOption(StrOption):
if len(splitted) == 1:
domain = splitted[0]
port = {'http': '80',
- 'https': '443'}[type]
+ 'https': '443'}[type_]
else:
domain, port = splitted
return domain, port, files
@@ -120,7 +122,7 @@ class URLOption(StrOption):
raise ValueError(_('must ends with a valid resource name'))
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
portoption = self.impl_get_extra('_port')
portoption.second_level_validation(port, warnings_only)
diff --git a/tiramisu/option/usernameoption.py b/tiramisu/option/usernameoption.py
index 1d846c0..89d5066 100644
--- a/tiramisu/option/usernameoption.py
+++ b/tiramisu/option/usernameoption.py
@@ -18,6 +18,8 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
+"""UsernameOption or GroupnameOption to check unix username/group value
+"""
import re
from ..i18n import _
@@ -25,14 +27,16 @@ from .stroption import RegexpOption
class UsernameOption(RegexpOption):
+ """UsernameOption to check unix username value
+ """
__slots__ = tuple()
#regexp build with 'man 8 adduser' informations
_regexp = re.compile(r"^[a-z_][a-z0-9_-]{0,30}[$a-z0-9_-]{0,1}$")
- _type = 'username'
- _display_name = _('unix username')
+ _type = _('unix username')
class GroupnameOption(UsernameOption):
+ """GroupnameOption to check unix group value
+ """
__slots__ = tuple()
- _type = 'groupname'
- _display_name = _('unix groupname')
+ _type = _('unix groupname')
diff --git a/tiramisu/setting.py b/tiramisu/setting.py
index e5fd0f1..22751a2 100644
--- a/tiramisu/setting.py
+++ b/tiramisu/setting.py
@@ -15,94 +15,92 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
# ____________________________________________________________
-from typing import Union
+from typing import Union, Set
from itertools import chain
-from .error import PropertiesOptionError, ConstError, ConfigError, LeadershipError, display_list
+from .error import PropertiesOptionError, ConstError, ConfigError, LeadershipError
from .i18n import _
-"""If cache and expire is enable, time before cache is expired.
-This delay start first time value/setting is set in cache, even if
-user access several time to value/setting
-"""
+# If cache and expire is enable, time before cache is expired.
+# This delay start first time value/setting is set in cache, even if
+# user access several time to value/setting
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
-an Option and for the Config together, Setting raise a PropertiesOptionError
-
-* Common properties:
-
-hidden
- option with this property can only get value in read only mode. This
- option is not available in read write mode.
-
-disabled
- option with this property cannot be set/get
-
-frozen
- cannot set value for option with this properties if 'frozen' is set in
- config
-
-* Special property:
-
-permissive
- option with 'permissive' cannot raise PropertiesOptionError for properties
- set in permissive
- config with 'permissive', whole option in this config cannot raise
- PropertiesOptionError for properties set in permissive
-
-mandatory
- should set value for option with this properties if 'mandatory' is set in
- config
- example: 'a', ['a'], [None] are valid
- None, [] are not valid
-
-empty
- raise mandatory PropertiesOptionError if multi or leader have empty value
- example: ['a'] is valid
- [None] is not valid
-
-unique
- raise ValueError if a value is set twice or more in a multi Option
-
-* Special Config properties:
-
-cache
- if set, enable cache settings and values
-
-expire
- if set, settings and values in cache expire after ``expiration_time``
-
-everything_frozen
- whole option in config are frozen (even if option have not frozen
- property)
-
-validator
- launch validator set by user in option (this property has no effect
- for internal validator)
-
-warnings
- display warnings during validation
-
-demoting_error_warning
- all value errors are convert to warning (ValueErrorWarning)
-"""
+#List of default properties (you can add new one if needed).
+#
+#For common properties and personalise properties, if a propery is set for
+#an Option and for the Config together, Setting raise a PropertiesOptionError
+#
+#* Common properties:
+#
+#hidden
+# option with this property can only get value in read only mode. This
+# option is not available in read write mode.
+#
+#disabled
+# option with this property cannot be set/get
+#
+#frozen
+# cannot set value for option with this properties if 'frozen' is set in
+# config
+#
+#* Special property:
+#
+#permissive
+# option with 'permissive' cannot raise PropertiesOptionError for properties
+# set in permissive
+# config with 'permissive', whole option in this config cannot raise
+# PropertiesOptionError for properties set in permissive
+#
+#mandatory
+# should set value for option with this properties if 'mandatory' is set in
+# config
+# example: 'a', ['a'], [None] are valid
+# None, [] are not valid
+#
+#empty
+# raise mandatory PropertiesOptionError if multi or leader have empty value
+# example: ['a'] is valid
+# [None] is not valid
+#
+#unique
+# raise ValueError if a value is set twice or more in a multi Option
+#
+#* Special Config properties:
+#
+#cache
+# if set, enable cache settings and values
+#
+#expire
+# if set, settings and values in cache expire after ``expiration_time``
+#
+#everything_frozen
+# whole option in config are frozen (even if option have not frozen
+# property)
+#
+#validator
+# launch validator set by user in option (this property has no effect
+# for internal validator)
+#
+#warnings
+# display warnings during validation
+#
+#demoting_error_warning
+# all value errors are convert to warning (ValueErrorWarning)
DEFAULT_PROPERTIES = frozenset(['cache', 'validator', 'warnings'])
SPECIAL_PROPERTIES = {'frozen', 'mandatory', 'empty', 'force_store_value'}
-"""Config can be in two defaut mode:
-
-read_only
- 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
- of this variable can change
- you cannot access to mandatory variable without values
-
-read_write
- you can get all variables not disabled and not hidden
- you can set all variables not frozen
-"""
+#Config can be in two defaut mode:
+#
+#read_only
+# 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
+# of this variable can change
+# you cannot access to mandatory variable without values
+#
+#read_write
+# you can get all variables not disabled and not hidden
+# you can set all variables not frozen
RO_APPEND = frozenset(['frozen',
'disabled',
'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
return 'Undefined'
@@ -158,6 +159,8 @@ undefined = Undefined()
class OptionBag:
+ """Object to store information for an option
+ """
__slots__ = ('option', # current option
'path',
'index',
@@ -167,6 +170,7 @@ class OptionBag:
'apply_requires', # apply requires or not for this option
)
+ # pylint: disable=too-many-arguments
def __init__(self,
option,
index,
@@ -187,42 +191,39 @@ class OptionBag:
self.path = path
elif option:
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
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:
self.properties = properties
def __getattr__(self, key):
if key == 'ori_option':
return self.option
- elif key == 'apply_requires':
+ if key == 'apply_requires':
return True
- return undefined
-
- 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
+ return None
def copy(self):
+ """copy OptionBag
+ """
option_bag = OptionBag(None,
None,
None,
)
for key in self.__slots__:
- if not hasattr(self, key):
- continue
setattr(option_bag, key, getattr(self, key))
return option_bag
class ConfigBag:
+ """Object to store information for context
+ """
__slots__ = ('context', # link to the current context
'properties', # properties for current context
'true_properties', # properties for current context
@@ -246,30 +247,37 @@ class ConfigBag:
if key == 'true_properties':
return self.properties
if key == 'expiration_time':
- self.expiration_time = EXPIRATION_TIME
+ self.expiration_time = EXPIRATION_TIME # pylint: disable=attribute-defined-outside-init
return self.expiration_time
if key == 'is_unrestraint':
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):
- super().__setattr__(key, value)
-
- def remove_warnings(self):
+ def nowarnings(self):
+ """do not warnings
+ """
self.properties = frozenset(self.properties - {'warnings'})
def remove_validation(self):
+ """do not validate option
+ """
self.properties = frozenset(self.properties - {'validator'})
def unrestraint(self):
- self.is_unrestraint = True
- self.true_properties = self.properties
+ """do not restraint access to option
+ """
+ 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'])
def set_permissive(self):
+ """set permissive
+ """
self.properties = frozenset(self.properties | {'permissive'})
def copy(self):
+ """copy the config
+ """
kwargs = {}
for key in self.__slots__:
kwargs[key] = getattr(self, key)
@@ -277,7 +285,7 @@ class ConfigBag:
# ____________________________________________________________
-class _NameSpace(object):
+class _NameSpace:
"""convenient class that emulates a module
and builds constants (that is, unique names)
when attribute is added, we cannot delete it
@@ -299,28 +307,27 @@ class _NameSpace(object):
class GroupModule(_NameSpace):
"emulates a module to manage unique group (OptionDescription) names"
+ # pylint: disable=too-few-public-methods
class GroupType(str):
"""allowed normal group (OptionDescription) names
*normal* means : groups that are not leader
"""
- pass
class DefaultGroupType(GroupType):
"""groups that are default (typically 'default')"""
- pass
class LeadershipGroupType(GroupType):
"""allowed normal group (OptionDescription) names
*leadership* means : groups that have the 'leadership' attribute set
"""
- pass
class RootGroupType(GroupType):
"""root means this is the root optiondescription of whole config
"""
- pass
def addgroup(self, name):
+ """add a new group type
+ """
setattr(groups, name, groups.GroupType(name))
@@ -329,14 +336,13 @@ class OwnerModule(_NameSpace):
owners are living in `Config._value_owners`
"""
+ # pylint: disable=too-few-public-methods
class Owner(str):
"""allowed owner names
"""
- pass
class DefaultOwner(Owner):
"""groups that are default (typically 'default')"""
- pass
def addowner(self, name):
"""
@@ -348,41 +354,39 @@ class OwnerModule(_NameSpace):
# ____________________________________________________________
# populate groups
groups = GroupModule()
-"""groups.default
- default group set when creating a new optiondescription"""
-groups.default = groups.DefaultGroupType('default')
-"""groups.leadership
- leadership group is a special optiondescription, all suboptions should
- 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.default: default group set when creating a new optiondescription
+groups.default = groups.DefaultGroupType('default') # pylint: disable=attribute-defined-outside-init
-""" groups.root
- this group is the root optiondescription of whole config"""
-groups.root = groups.RootGroupType('root')
+# groups.leadership: leadership group is a special optiondescription, all suboptions should
+# 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') # 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
owners = OwnerModule()
-"""default
- is the config owner after init time"""
-owners.default = owners.DefaultOwner('default')
-"""user
- is the generic is the generic owner"""
-owners.user = owners.Owner('user')
-"""forced
- special owner when value is forced"""
-owners.forced = owners.Owner('forced')
+
+# default: is the config owner after init time
+owners.default = owners.DefaultOwner('default') # pylint: disable=attribute-defined-outside-init
+
+# user: is the generic is the generic owner
+owners.addowner('user')
+
+#forced: special owner when value is 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"
__slots__ = ('_properties',
'_permissives',
@@ -417,33 +421,33 @@ class Settings(object):
def get_context_properties(self,
cache,
):
- is_cached, props, validated = cache.getcache(None,
- None,
- None,
- {},
- {},
- 'context_props',
- )
+ """get context properties
+ """
+ is_cached, props, _ = cache.getcache(None,
+ 'context_props',
+ expiration=False,
+ )
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,
- None,
props,
- {},
- props,
- True)
+ type_='properties',
+ )
return props
- def _getproperties(self,
- path,
- index,
- default_properties,
- ):
- if path not in self._properties:
- ret = frozenset(default_properties)
- else:
- ret = self._properties[path].get(index, frozenset(default_properties))
- return ret
+ def get_stored_properties(self,
+ path: Union[None, str],
+ index: Union[None, int],
+ default_properties: Set[str],
+ ) -> Set[str]:
+ """Get the properties modified by user for a path or index
+ """
+ if path not in self._properties or index not in self._properties[path]:
+ return frozenset(default_properties)
+ return self._properties[path][index]
def getproperties(self,
option_bag,
@@ -451,21 +455,15 @@ class Settings(object):
uncalculated=False,
help_property=False,
):
+ """get properties
"""
- """
+ # pylint: disable=too-many-branches
option = option_bag.option
- config_bag = option_bag.config_bag
if option.impl_is_symlinkoption():
option = option.impl_getopt()
- path = option.impl_getpath()
- index = option_bag.index
if apply_requires and not uncalculated and not help_property:
- cache = config_bag.context.properties_cache
- is_cached, props, validated = cache.getcache(path,
- config_bag.expiration_time,
- index,
- config_bag.properties,
- {},
+ cache = option_bag.config_bag.context.properties_cache
+ is_cached, props, validated = cache.getcache(option_bag, # pylint: disable=unused-variable
'self_props',
)
else:
@@ -473,13 +471,16 @@ class Settings(object):
if not is_cached:
props = set()
# if index, get option's properties (without index) too
- p_props = self._getproperties(path,
- None,
- option.impl_getproperties(),
- )
- if index is not None:
+ p_props = self.get_stored_properties(option_bag.path,
+ None,
+ option.impl_getproperties(),
+ )
+ if option_bag.index is not None:
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:
if uncalculated or isinstance(prop, str):
@@ -502,43 +503,29 @@ class Settings(object):
new_prop = (new_prop, new_prop)
if new_prop is None:
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)):
- raise ValueError(_('invalid property type {} for {} with {} function').format(type(new_prop),
- option_bag.option.impl_getname(),
- prop.function.__name__))
+ raise ValueError(_('invalid property type {type(new_prop)} for '
+ '{option_bag.option.impl_getname()} with '
+ '{prop.function.__name__} function'))
if not option.impl_is_optiondescription() and \
option.impl_is_leader() and \
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 -= self.getpermissives(option_bag)
- if not uncalculated and apply_requires and not config_bag.is_unrestraint and not help_property:
- cache.setcache(path,
- index,
+ if not uncalculated and apply_requires and \
+ not option_bag.config_bag.is_unrestraint and \
+ not help_property:
+ cache.setcache(option_bag,
props,
- props,
- config_bag.properties,
- True)
+ type_='properties',
+ )
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):
+ """get context permissives
+ """
return self.getpermissives(None)
def _getpermissives(self,
@@ -554,6 +541,8 @@ class Settings(object):
def getpermissives(self,
option_bag,
):
+ """get permissive
+ """
if option_bag is None:
path = None
index = None
@@ -576,6 +565,8 @@ class Settings(object):
#____________________________________________________________
# set methods
def set_context_properties(self, properties, context):
+ """set context properties
+ """
self._properties.setdefault(None, {})[None] = properties
context.reset_cache(None)
@@ -587,21 +578,16 @@ class Settings(object):
(never save properties if same has option properties)
"""
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():
not_allowed_properties = properties - ALLOWED_LEADER_PROPERTIES
if not_allowed_properties:
- if len(not_allowed_properties) == 1:
- raise LeadershipError(_('leader cannot have "{}" property').format(list(not_allowed_properties)[0]))
- else:
- raise LeadershipError(_('leader cannot have {} properties').format(display_list(list(not_allowed_properties), add_quote=True)))
- if ('force_default_on_freeze' in properties or 'force_metaconfig_on_freeze' in properties) and \
- 'frozen' not in properties:
- raise LeadershipError(_('a leader ({0}) cannot have '
- '"force_default_on_freeze" or "force_metaconfig_on_freeze" property without "frozen"'
- '').format(opt.impl_get_display_name()))
+ raise LeadershipError(_('leader cannot have "{list(not_allowed_properties)}" '
+ 'property'))
+ if ('force_default_on_freeze' in properties or \
+ 'force_metaconfig_on_freeze' in properties) and 'frozen' not in properties:
+ raise LeadershipError(_('a leader ({opt.impl_get_display_name()}) cannot have '
+ '"force_default_on_freeze" or '
+ '"force_metaconfig_on_freeze" property without "frozen"'))
self._properties.setdefault(option_bag.path, {})[option_bag.index] = properties
# values too because of follower values could have a PropertiesOptionError has value
option_bag.config_bag.context.reset_cache(option_bag)
@@ -610,6 +596,8 @@ class Settings(object):
def set_context_permissives(self,
permissives,
):
+ """set context permissive
+ """
self.setpermissives(None,
permissives,
)
@@ -630,10 +618,6 @@ class Settings(object):
if not isinstance(permissives, frozenset):
raise TypeError(_('permissive must be a frozenset'))
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
index = option_bag.index
else:
@@ -670,25 +654,29 @@ class Settings(object):
def reset(self,
bag: Union[OptionBag, ConfigBag],
):
+ """reset property
+ """
path, index, config_bag, option_bag = \
self._get_path_index_config_option(bag,
"can't reset properties to "
"the symlinkoption \"{}\"",
)
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)
def reset_permissives(self,
bag: Union[OptionBag, ConfigBag],
):
+ """reset permission
+ """
path, index, config_bag, option_bag = \
self._get_path_index_config_option(bag,
"can't reset permissives to "
"the symlinkoption \"{}\"",
)
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)
#____________________________________________________________
@@ -698,6 +686,8 @@ class Settings(object):
apply_requires=True,
uncalculated=False,
):
+ """raise if needed
+ """
if not uncalculated and apply_requires:
option_properties = option_bag.properties
else:
@@ -707,12 +697,14 @@ class Settings(object):
)
return self._calc_raises_properties(option_bag.config_bag.properties,
option_bag.config_bag.permissives,
- option_properties)
+ option_properties,
+ )
def _calc_raises_properties(self,
context_properties,
context_permissives,
- option_properties):
+ option_properties,
+ ):
raises_properties = context_properties - SPECIAL_PROPERTIES
# remove global permissive properties
if raises_properties and 'permissive' in raises_properties:
@@ -725,6 +717,8 @@ class Settings(object):
option_bag,
need_help=True,
):
+ """check properties
+ """
config_properties = option_bag.config_bag.properties
if not config_properties or config_properties == frozenset(['cache']):
# if no global property
@@ -747,49 +741,52 @@ class Settings(object):
raise PropertiesOptionError(option_bag,
properties,
self,
- help_properties=calc_properties)
+ help_properties=calc_properties,
+ )
def validate_mandatory(self,
value,
option_bag,
):
- if 'mandatory' in option_bag.config_bag.properties:
- values = option_bag.config_bag.context.get_values()
- if option_bag.option.impl_is_follower():
- force_allow_empty_list = True
- else:
- force_allow_empty_list = False
- if not ('permissive' in option_bag.config_bag.properties and
- 'mandatory' in option_bag.config_bag.permissives) and \
- 'mandatory' in option_bag.properties and values.isempty(option_bag.option,
- value,
- force_allow_empty_list=force_allow_empty_list,
- index=option_bag.index,
- ):
- raise PropertiesOptionError(option_bag,
- ['mandatory'],
- self,
- )
- if 'empty' in option_bag.properties and values.isempty(option_bag.option,
- value,
- force_allow_empty_list=True,
- index=option_bag.index,
- ):
- raise PropertiesOptionError(option_bag,
- ['empty'],
- self,
- )
+ """verify if option is mandatory without value
+ """
+ if 'mandatory' not in option_bag.config_bag.properties:
+ return
+ values = option_bag.config_bag.context.get_values()
+ if not ('permissive' in option_bag.config_bag.properties and
+ 'mandatory' in option_bag.config_bag.permissives) and \
+ 'mandatory' in option_bag.properties and values.isempty(option_bag,
+ value,
+ False,
+ ):
+ raise PropertiesOptionError(option_bag,
+ ['mandatory'],
+ self,
+ )
+ if 'empty' in option_bag.properties and values.isempty(option_bag,
+ value,
+ True,
+ ):
+ raise PropertiesOptionError(option_bag,
+ ['empty'],
+ self,
+ )
def validate_frozen(self,
- option_bag):
+ option_bag,
+ ):
+ """verify if option is frozen
+ """
if option_bag.config_bag.properties and \
('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
'frozen' in option_bag.config_bag.permissives):
raise PropertiesOptionError(option_bag,
['frozen'],
- self)
+ self,
+ )
return False
#____________________________________________________________
# read only/read write
@@ -799,7 +796,10 @@ class Settings(object):
append,
config_bag,
):
- props = self._properties.get(None, {}).get(None, self.default_properties)
+ props = self.get_stored_properties(None,
+ None,
+ self.default_properties,
+ )
modified = False
if remove & props:
props = props - remove
diff --git a/tiramisu/todict.py b/tiramisu/todict.py
index 1dcebf3..c484f4a 100644
--- a/tiramisu/todict.py
+++ b/tiramisu/todict.py
@@ -207,7 +207,7 @@ class Requires(object):
else:
act = 'hide'
inv_act = 'show'
- if option.get_type() == 'choice':
+ if isinstance(option, ChoiceOption):
require_option = self.tiramisu_web.config.unrestraint.option(option_path)
values = self.tiramisu_web.get_enum(require_option,
require_option.option.ismulti(),
diff --git a/tiramisu/value.py b/tiramisu/value.py
index 9a0744e..b0009f2 100644
--- a/tiramisu/value.py
+++ b/tiramisu/value.py
@@ -15,39 +15,37 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
# ____________________________________________________________
-import weakref
-from typing import Optional, Any, Callable
-from .error import ConfigError, PropertiesOptionError
-from .setting import owners, undefined, forbidden_owners, OptionBag, ConfigBag
-from .autolib import Calculation, carry_out_calculation, Params
+from typing import Union, Optional, List, Any
+from .error import ConfigError
+from .setting import owners, undefined, forbidden_owners, OptionBag
+from .autolib import Calculation
from .i18n import _
class Values:
- """The `Config`'s root is indeed in charge of the `Option()`'s values,
- but the values are physicaly located here, in `Values`, wich is also
- responsible of a caching utility.
+ """This class manage value (default value, stored value or calculated value
+ It's also responsible of a caching utility.
"""
+ # pylint: disable=too-many-public-methods
__slots__ = ('_values',
'_informations',
'__weakref__',
)
def __init__(self,
- default_values=None,
- ):
+ default_values: Union[None, dict]=None,
+ ) -> None:
"""
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 = {}
# set default owner
if not default_values:
- self._values = {None: {None: [None, owners.user]}}
- else:
- self._values = default_values
+ default_values = {None: {None: [None, owners.user]}}
+ self._values = default_values
#______________________________________________________________________
# get value
@@ -61,17 +59,13 @@ class Values:
"""
# try to retrive value in cache
setting_properties = option_bag.config_bag.properties
- cache = option_bag.config_bag.context._impl_values_cache
- is_cached, value, validated = cache.getcache(option_bag.path,
- option_bag.config_bag.expiration_time,
- option_bag.index,
- setting_properties,
- option_bag.properties,
- 'value',
+ cache = option_bag.config_bag.context.get_values_cache()
+ is_cached, value, validated = cache.getcache(option_bag,
+ 'values',
)
# no cached value so get value
if not is_cached:
- value = self.getvalue(option_bag)
+ value = self.get_value(option_bag)
# validates and warns value
if not validated:
validate = option_bag.option.impl_validate(value,
@@ -85,12 +79,9 @@ class Values:
)
# set value to cache
if not is_cached:
- cache.setcache(option_bag.path,
- option_bag.index,
+ cache.setcache(option_bag,
value,
- option_bag.properties,
- setting_properties,
- validate,
+ validated=validate,
)
if isinstance(value, list):
# return a copy, so value cannot be modified
@@ -98,81 +89,28 @@ class Values:
# and return it
return value
- def force_to_metaconfig(self, option_bag):
- # force_metaconfig_on_freeze in config => to metaconfig
- # force_metaconfig_on_freeze in option + config is kernelconfig => to metaconfig
- settings = option_bag.config_bag.context.get_settings()
- 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`
+ def get_value(self,
+ option_bag: OptionBag,
+ ) -> Any:
+ """actually retrieves the stored value or the default value (value modified by user)
:returns: value
"""
-
# get owner and value from store
- # index allowed only for follower
- index = option_bag.index
- 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])
+ default_value = [undefined, owners.default]
+ value, owner = self._values.get(option_bag.path, {}).get(option_bag.index, default_value)
if owner == owners.default or \
('frozen' in option_bag.properties and \
- ('force_default_on_freeze' in option_bag.properties or self.force_to_metaconfig(option_bag))):
- value = self.getdefaultvalue(option_bag)
- else:
- value = self.calc_value(option_bag, value)
+ ('force_default_on_freeze' in option_bag.properties or \
+ self.check_force_to_metaconfig(option_bag))):
+ # the value is a default value
+ # get it
+ value = self.get_default_value(option_bag)
return value
- def calc_value(self,
- option_bag,
- value,
- 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,
- ):
+ def get_default_value(self,
+ option_bag: OptionBag,
+ ) -> Any:
"""get default value:
- get parents config value or
- get calculated value or
@@ -183,45 +121,84 @@ class Values:
# retrieved value from parent config
return moption_bag.config_bag.context.get_values().get_cached_value(moption_bag)
- # now try to get default value:
- value = self.calc_value(option_bag,
- option_bag.option.impl_getdefault(),
- )
- if option_bag.index is not None and isinstance(value, (list, tuple)):
- if value and option_bag.option.impl_is_submulti():
- # first index is a list, assume other data are list too
- if isinstance(value[0], list):
- # 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())
- 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())
+ # now try to get calculated value:
+ value = self.get_calculated_value(option_bag,
+ option_bag.option.impl_getdefault(),
+ )
+ if option_bag.index is not None and isinstance(value, (list, tuple)) \
+ and (not option_bag.option.impl_is_submulti() or \
+ not value or isinstance(value[0], list)):
+ # if index (so slave), 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:
+ 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.get_calculated_value(option_bag,
+ option_bag.option.impl_getdefault_multi(),
+ )
return value
- def calculate_reset_cache(self,
- option_bag,
- value):
- if not 'expire' in option_bag.properties:
- return
- cache = option_bag.config_bag.context._impl_values_cache
- is_cache, cache_value, validated = cache.getcache(option_bag.path,
- None,
- option_bag.index,
- option_bag.config_bag.properties,
- option_bag.properties,
- 'value')
+ def get_calculated_value(self,
+ option_bag,
+ value,
+ reset_cache=True,
+ ) -> Any:
+ """value could be a calculation, in this case do calculation
+ """
+ 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()}": '
+ 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:
# calculation return same value as previous value,
# so do not invalidate cache
@@ -232,30 +209,47 @@ class Values:
self._set_force_value_suffix(option_bag)
def isempty(self,
- opt,
- value,
- force_allow_empty_list=False,
- index=None):
- "convenience method to know if an option is empty"
- empty = opt._empty
- if index in [None, undefined] and opt.impl_is_multi():
- isempty = value is None or (isinstance(value, list) and not force_allow_empty_list and value == []) or \
- (isinstance(value, list) and None in value) or empty in value
+ option_bag: OptionBag,
+ value: Any,
+ force_allow_empty_list: bool,
+ ) -> bool:
+ """convenience method to know if an option is empty
+ """
+ if option_bag.index is None and option_bag.option.impl_is_submulti():
+ # index is not set
+ 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:
- isempty = value is None or value == empty or (opt.impl_is_submulti() and value == [])
+ isempty = value is None or value == ''
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
def set_value(self,
- option_bag,
- value,
- ):
- context = option_bag.config_bag.context
+ option_bag: OptionBag,
+ value: Any,
+ ) -> None:
+ """set value to option
+ """
owner = self.get_context_owner()
if 'validator' in option_bag.config_bag.properties:
self.setvalue_validation(value,
- option_bag)
+ option_bag,
+ )
if isinstance(value, list):
# copy
@@ -265,33 +259,35 @@ class Values:
owner,
)
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:
- cache = option_bag.config_bag.context._impl_values_cache
- cache.setcache(option_bag.path,
- option_bag.index,
+ cache = option_bag.config_bag.context.get_values_cache()
+ cache.setcache(option_bag,
value,
- option_bag.properties,
- setting_properties,
- validator)
+ validated=validator,
+ )
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,
- value,
- option_bag,
- owners.forced,
- )
+ leader = option_bag.option.impl_get_leadership()
+ leader.follower_force_store_value(value,
+ option_bag.config_bag,
+ owners.forced,
+ )
def setvalue_validation(self,
value,
option_bag,
):
+ """validate value before set value
+ """
settings = option_bag.config_bag.context.get_settings()
# First validate properties with this value
opt = option_bag.option
settings.validate_frozen(option_bag)
- val = self.calc_value(option_bag,
- value,
- False,)
+ val = self.get_calculated_value(option_bag,
+ value,
+ False,
+ )
settings.validate_mandatory(val,
option_bag,
)
@@ -320,25 +316,25 @@ class Values:
)
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,
path,
index,
value,
owner,
):
+ """set a value
+ """
self._values.setdefault(path, {})[index] = [value, owner]
- def _set_force_value_suffix(self,
- option_bag: OptionBag,
- ) -> None:
+ def _set_force_value_suffix(self, option_bag: OptionBag) -> None:
+ """ force store value for an option for suffixes
+ """
+ # pylint: disable=too-many-locals
if 'force_store_value' not in option_bag.config_bag.properties:
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()
force_store_options = []
for coption in option.get_children_recursively(None,
@@ -350,10 +346,10 @@ class Values:
if not force_store_options:
continue
rootpath = option.impl_getpath()
- settings = option_bag.config_bag.context.get_settings()
for suffix in option.get_suffixes(option_bag.config_bag):
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)
subpath = '.'.join([subp + path_suffix for subp in subpaths])
doption = coption.to_dynoption(subpath,
@@ -367,7 +363,7 @@ class Values:
option_bag.config_bag,
properties=frozenset(),
)
- indexes = range(len(self.getvalue(loption_bag)))
+ indexes = range(len(self.get_value(loption_bag)))
else:
indexes = [None]
for index in indexes:
@@ -375,7 +371,8 @@ class Values:
index,
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,
option_bag: OptionBag,
@@ -398,8 +395,9 @@ class Values:
# remove force_metaconfig_on_freeze only if option in metaconfig
# hasn't force_metaconfig_on_freeze properties
ori_properties = doption_bag.properties
- doption_bag.properties = doption_bag.config_bag.context.get_settings().getproperties(doption_bag)
- if not self.force_to_metaconfig(doption_bag):
+ settings = doption_bag.config_bag.context.get_settings()
+ 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'}
else:
doption_bag.properties = ori_properties
@@ -416,11 +414,15 @@ class Values:
# owner
def is_default_owner(self,
- option_bag,
- validate_meta=True):
+ option_bag: OptionBag,
+ validate_meta: bool=True,
+ ) -> bool:
+ """is default owner for an option
+ """
return self.getowner(option_bag,
validate_meta=validate_meta,
- only_default=True) == owners.default
+ only_default=True,
+ ) == owners.default
def hasvalue(self,
path,
@@ -432,7 +434,7 @@ class Values:
has_path = path in self._values
if index is None:
return has_path
- elif has_path:
+ if has_path:
return index in self._values[path]
return False
@@ -468,14 +470,18 @@ class Values:
else:
owner = owners.default
else:
- owner = self._values.get(option_bag.path, {}).get(option_bag.index, [undefined, owners.default])[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):
+ owner = self._values.get(option_bag.path, {}).get(option_bag.index,
+ [undefined, owners.default],
+ )[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)
if moption_bag is not None:
- owner = moption_bag.config_bag.context.get_values().getowner(moption_bag,
- only_default=only_default,
- )
+ values = moption_bag.config_bag.context.get_values()
+ owner = values.getowner(moption_bag,
+ only_default=only_default,
+ )
elif 'force_metaconfig_on_freeze' in option_bag.properties:
return owners.default
return owner
@@ -487,32 +493,28 @@ class Values:
"""
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
"""
- 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:
raise ValueError(_('set owner "{0}" is forbidden').format(str(owner)))
if not self.hasvalue(option_bag.path, option_bag.index):
- raise ConfigError(_('no value for {0} cannot change owner to {1}'
- '').format(option_bag.path, owner))
+ raise ConfigError(_(f'no value for {option_bag.path} cannot change owner to {owner}'))
option_bag.config_bag.context.get_settings().validate_frozen(option_bag)
self._values[option_bag.path][option_bag.index][1] = owner
#______________________________________________________________________
# reset
- def reset(self,
- option_bag):
+ def reset(self, option_bag: OptionBag) -> None:
+ """reset value for an option
+ """
context = option_bag.config_bag.context
hasvalue = self.hasvalue(option_bag.path)
setting_properties = 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.remove_validation()
config_bag.context = fake_context
@@ -521,16 +523,17 @@ class Values:
fake_value = fake_context.get_values()
fake_value.reset(soption_bag)
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,
- soption_bag)
+ soption_bag,
+ )
opt = option_bag.option
if opt.impl_is_leader():
- opt.impl_get_leadership().reset(self,
- option_bag)
+ opt.impl_get_leadership().reset(option_bag.config_bag)
if hasvalue:
- if 'force_store_value' in option_bag.config_bag.properties and 'force_store_value' in option_bag.properties:
- value = self.getdefaultvalue(option_bag)
+ if 'force_store_value' in option_bag.config_bag.properties and \
+ 'force_store_value' in option_bag.properties:
+ value = self.get_default_value(option_bag)
self._setvalue(option_bag,
value,
@@ -544,72 +547,89 @@ class Values:
context.reset_cache(option_bag)
if 'force_store_value' in setting_properties and option_bag.option.impl_is_leader():
if value is None:
- value = self.getdefaultvalue(option_bag)
- option_bag.option.impl_get_leadership().follower_force_store_value(self,
- value,
- option_bag,
- owners.forced)
+ value = self.get_default_value(option_bag)
+ leader = option_bag.option.impl_get_leadership()
+ leader.follower_force_store_value(value,
+ option_bag.config_bag,
+ 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, {})
if values:
return max(values) + 1
return 0
def reset_follower(self,
- option_bag):
- if self.hasvalue(option_bag.path,
- index=option_bag.index):
- context = option_bag.config_bag.context
- setting_properties = option_bag.config_bag.properties
- if 'validator' in setting_properties:
- fake_context = context._gen_fake_values()
- fake_value = fake_context.get_values()
- config_bag = option_bag.config_bag.copy()
- config_bag.remove_validation()
- config_bag.context = fake_context
- soption_bag = option_bag.copy()
- soption_bag.config_bag = config_bag
- fake_value.reset_follower(soption_bag)
- value = fake_value.getdefaultvalue(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.getdefaultvalue(option_bag)
+ option_bag: OptionBag,
+ ) -> None:
+ """reset value for a follower
+ """
+ if not self.hasvalue(option_bag.path,
+ index=option_bag.index,
+ ):
+ return
+ context = option_bag.config_bag.context
+ setting_properties = option_bag.config_bag.properties
+ if 'validator' in setting_properties:
+ fake_context = context.gen_fake_values()
+ fake_value = fake_context.get_values()
+ config_bag = option_bag.config_bag.copy()
+ config_bag.remove_validation()
+ config_bag.context = fake_context
+ soption_bag = option_bag.copy()
+ soption_bag.config_bag = config_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,
- value,
- owners.forced,
- )
- else:
- self.resetvalue_index(option_bag.path,
- option_bag.index,
- )
- context.reset_cache(option_bag)
+ self._setvalue(option_bag,
+ value,
+ owners.forced,
+ )
+ else:
+ self.resetvalue_index(option_bag)
+ context.reset_cache(option_bag)
- def resetvalue_index(self,
- path,
- index,
- ):
- if path in self._values and index in self._values[path]:
- del self._values[path][index]
+ def resetvalue_index(self, option_bag: OptionBag) -> None:
+ """reset a value for a follower at an index
+ """
+ if option_bag.path in self._values and option_bag.index in self._values[option_bag.path]:
+ del self._values[option_bag.path][option_bag.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,
option_bag: OptionBag,
leadership_option_bag: OptionBag,
index: int,
- ):
+ ) -> None:
+ """reset leadershop from an index
+ """
current_value = self.get_cached_value(option_bag)
length = len(current_value)
if index >= length:
- raise IndexError(_('index {} is greater than the length {} '
- 'for option "{}"').format(index,
- length,
- option_bag.option.impl_get_display_name()))
+ raise IndexError(_('index {index} is greater than the length {length} '
+ 'for option "{option_bag.option.impl_get_display_name()}"'))
current_value.pop(index)
- leadership_option_bag.option.pop(self,
- index,
- option_bag,
+ leadership_option_bag.option.pop(index,
+ option_bag.config_bag,
)
self.set_value(option_bag,
current_value,
@@ -619,7 +639,6 @@ class Values:
# information
def set_information(self,
- config_bag,
option_bag,
key,
value,
@@ -634,55 +653,62 @@ class Values:
else:
path = option_bag.path
self._informations.setdefault(path, {})[key] = value
- if path is not None:
- for option in option_bag.option.get_dependencies_information(itself=True):
- config_bag.context.reset_cache(option_bag)
+ if path is None:
+ return
+ if key in option_bag.option.get_dependencies_information(itself=True):
+ option_bag.config_bag.context.reset_cache(option_bag)
def get_information(self,
- config_bag,
option_bag,
- key,
+ name,
default,
):
"""retrieves one information's item
- :param key: the item string (ex: "help")
+ :param name: the item string (ex: "help")
"""
if option_bag is None:
path = None
else:
path = option_bag.path
try:
- return self._informations[path][key]
+ return self._informations[path][name]
except KeyError as err:
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:
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,
- key,
- raises=True,
- path=None,
+ key: Any,
+ raises: bool=True,
+ path: str=None,
):
+ """delete information for a specified key
+ """
if path in self._informations and key in self._informations[path]:
del self._informations[path][key]
elif raises:
raise ValueError(_(f"information's item not found \"{key}\""))
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())
#____________________________________________________________
# default owner methods
- def set_context_owner(self, owner):
- ":param owner: sets the default value for owner at the Config level"
+ def set_context_owner(self, owner: str) -> None:
+ """set the context owner
+ """
if owner in forbidden_owners:
raise ValueError(_('set owner "{0}" is forbidden').format(str(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]