add Calculation to properties

This commit is contained in:
Emmanuel Garette 2019-09-01 09:41:53 +02:00
parent 7c641961d3
commit bb2ecc94d9
27 changed files with 2358 additions and 574 deletions

View file

@ -5,12 +5,11 @@ from py.test import raises
from .autopath import do_autopath from .autopath import do_autopath
do_autopath() do_autopath()
from tiramisu.option import BoolOption, IPOption, IntOption, StrOption, OptionDescription, Leadership from tiramisu import BoolOption, IPOption, IntOption, StrOption, OptionDescription, Leadership, Config, \
from tiramisu import Config undefined, Calculation, Params, ParamValue, ParamOption, \
list_sessions, default_storage, delete_session, calc_value
from tiramisu.error import ConfigError, PropertiesOptionError from tiramisu.error import ConfigError, PropertiesOptionError
from tiramisu.setting import groups from tiramisu.setting import groups
from tiramisu import undefined, Params, ParamValue, ParamOption, \
list_sessions, default_storage, delete_session
def teardown_function(function): def teardown_function(function):
@ -497,8 +496,12 @@ def test_cache_leader_callback():
def test_cache_requires(): def test_cache_requires():
a = BoolOption('activate_service', '', True) a = BoolOption('activate_service', '', True)
b = IPOption('ip_address_service', '', disabled_property = Calculation(calc_value,
requires=[{'option': a, 'expected': False, 'action': 'disabled'}]) Params(ParamValue('disabled'),
kwargs={'condition': ParamOption(a),
'expected': ParamValue(False),
'default': ParamValue(None)}))
b = IPOption('ip_address_service', '', properties=(disabled_property,))
od = OptionDescription('service', '', [a, b]) od = OptionDescription('service', '', [a, b])
cfg = Config(od) cfg = Config(od)
cfg.property.read_write() cfg.property.read_write()
@ -545,8 +548,12 @@ def test_cache_requires():
def test_cache_global_properties(): def test_cache_global_properties():
a = BoolOption('activate_service', '', True) a = BoolOption('activate_service', '', True)
b = IPOption('ip_address_service', '', disabled_property = Calculation(calc_value,
requires=[{'option': a, 'expected': False, 'action': 'disabled'}]) Params(ParamValue('disabled'),
kwargs={'condition': ParamOption(a),
'expected': ParamValue(False),
'default': ParamValue(None)}))
b = IPOption('ip_address_service', '', properties=(disabled_property,))
od = OptionDescription('service', '', [a, b]) od = OptionDescription('service', '', [a, b])
cfg = Config(od) cfg = Config(od)
cfg.property.read_write() cfg.property.read_write()

View file

@ -131,7 +131,7 @@ def test_base_config_in_a_tree():
def test_not_valid_properties(): def test_not_valid_properties():
raises(TypeError, "stroption = StrOption('str', 'Test string option', default='abc', properties=['mandatory',])") raises(AssertionError, "stroption = StrOption('str', 'Test string option', default='abc', properties='mandatory')")
def test_information_config(): def test_information_config():

View file

@ -9,7 +9,7 @@ from tiramisu import BoolOption, StrOption, ChoiceOption, IPOption, \
UnicodeOption, PortOption, BroadcastOption, DomainnameOption, \ UnicodeOption, PortOption, BroadcastOption, DomainnameOption, \
EmailOption, URLOption, UsernameOption, FilenameOption, SymLinkOption, \ EmailOption, URLOption, UsernameOption, FilenameOption, SymLinkOption, \
OptionDescription, DynOptionDescription, SynDynOption, submulti, Leadership, \ OptionDescription, DynOptionDescription, SynDynOption, submulti, Leadership, \
Config, Params, ParamOption, ParamValue Config, Params, ParamOption, ParamValue, Calculation, calc_value
from tiramisu.error import PropertiesOptionError, ConfigError, ConflictError from tiramisu.error import PropertiesOptionError, ConfigError, ConflictError
from tiramisu.storage import list_sessions from tiramisu.storage import list_sessions
@ -494,16 +494,24 @@ def test_decrease_dyndescription_context():
def test_dyndescription_root(): def test_dyndescription_root():
boolean = BoolOption('boolean', '', True) boolean = BoolOption('boolean', '', True)
st1 = StrOption('st', '', requires=[{'option': boolean, 'expected': False, disabled_property = Calculation(calc_value,
'action': 'disabled'}]) Params(ParamValue('disabled'),
kwargs={'condition': ParamOption(boolean),
'expected': ParamValue(False),
'default': ParamValue(None)}))
st1 = StrOption('st', '', properties=(disabled_property,))
dod = DynOptionDescription('dod', '', [boolean, st1], callback=return_list) dod = DynOptionDescription('dod', '', [boolean, st1], callback=return_list)
raises(ConfigError, "Config(dod)") raises(ConfigError, "Config(dod)")
def test_requires_dyndescription(): def test_requires_dyndescription():
boolean = BoolOption('boolean', '', True) boolean = BoolOption('boolean', '', True)
st1 = StrOption('st', '', requires=[{'option': boolean, 'expected': False, disabled_property = Calculation(calc_value,
'action': 'disabled'}]) Params(ParamValue('disabled'),
kwargs={'condition': ParamOption(boolean, raisepropertyerror=True),
'expected': ParamValue(False),
'default': ParamValue(None)}))
st1 = StrOption('st', '', properties=(disabled_property,))
dod = DynOptionDescription('dod', '', [st1], callback=return_list) dod = DynOptionDescription('dod', '', [st1], callback=return_list)
od1 = OptionDescription('od', '', [dod]) od1 = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od1, boolean]) od2 = OptionDescription('od', '', [od1, boolean])
@ -547,11 +555,18 @@ def test_requires_dyndescription():
def test_requires_dyndescription_boolean(): def test_requires_dyndescription_boolean():
boolean1 = BoolOption('boolean1', '', True) boolean1 = BoolOption('boolean1', '', True)
boolean = BoolOption('boolean', '', True, requires=[{'option': boolean1, disabled_property = Calculation(calc_value,
'expected': False, Params(ParamValue('disabled'),
'action': 'disabled'}]) kwargs={'condition': ParamOption(boolean1, raisepropertyerror=True),
st = StrOption('st', '', requires=[{'option': boolean, 'expected': False, 'expected': ParamValue(False),
'action': 'disabled'}]) 'default': ParamValue(None)}))
boolean = BoolOption('boolean', '', True, properties=(disabled_property,))
disabled_property = Calculation(calc_value,
Params(ParamValue('disabled'),
kwargs={'condition': ParamOption(boolean, raisepropertyerror=True),
'expected': ParamValue(False),
'default': ParamValue(None)}))
st = StrOption('st', '', properties=(disabled_property,))
dod = DynOptionDescription('dod', '', [st], callback=return_list) dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod]) od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od, boolean1, boolean]) od2 = OptionDescription('od', '', [od, boolean1, boolean])
@ -578,8 +593,12 @@ def test_requires_dyndescription_boolean():
def test_requires_dyndescription_in_dyn(): def test_requires_dyndescription_in_dyn():
boolean = BoolOption('boolean', '', True) boolean = BoolOption('boolean', '', True)
st = StrOption('st', '', requires=[{'option': boolean, 'expected': False, disabled_property = Calculation(calc_value,
'action': 'disabled'}]) Params(ParamValue('disabled'),
kwargs={'condition': ParamOption(boolean, raisepropertyerror=True),
'expected': ParamValue(False),
'default': ParamValue(None)}))
st = StrOption('st', '', properties=(disabled_property,))
dod = DynOptionDescription('dod', '', [boolean, st], callback=return_list) dod = DynOptionDescription('dod', '', [boolean, st], callback=return_list)
od = OptionDescription('od', '', [dod]) od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od]) od2 = OptionDescription('od', '', [od])
@ -608,9 +627,12 @@ def test_requires_dyndescription_in_dyn():
def test_requires_dyndescription2(): def test_requires_dyndescription2():
boolean = BoolOption('boolean', '', True) boolean = BoolOption('boolean', '', True)
st1 = StrOption('st', '') st1 = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st1], callback=return_list, disabled_property = Calculation(calc_value,
requires=[{'option': boolean, 'expected': False, Params(ParamValue('disabled'),
'action': 'disabled'}]) kwargs={'condition': ParamOption(boolean, raisepropertyerror=True),
'expected': ParamValue(False),
'default': ParamValue(None)}))
dod = DynOptionDescription('dod', '', [st1], callback=return_list, properties=(disabled_property,))
od1 = OptionDescription('od', '', [dod]) od1 = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od1, boolean]) od2 = OptionDescription('od', '', [od1, boolean])
api = Config(od2) api = Config(od2)

View file

@ -8,7 +8,7 @@ from py.test import raises
from tiramisu.setting import owners, groups from tiramisu.setting import owners, groups
from tiramisu import ChoiceOption, BoolOption, IntOption, FloatOption, \ from tiramisu import ChoiceOption, BoolOption, IntOption, FloatOption, \
StrOption, OptionDescription, SymLinkOption, Leadership, Config, \ StrOption, OptionDescription, SymLinkOption, Leadership, Config, \
Params, ParamContext, ParamOption, ParamValue Calculation, Params, ParamContext, ParamOption, ParamValue, calc_value
from tiramisu.error import PropertiesOptionError, ConfigError from tiramisu.error import PropertiesOptionError, ConfigError
from tiramisu.storage import list_sessions from tiramisu.storage import list_sessions
@ -41,14 +41,23 @@ def make_description_freeze():
floatoption = FloatOption('float', 'Test float option', default=2.3) floatoption = FloatOption('float', 'Test float option', default=2.3)
stroption = StrOption('str', 'Test string option', default="abc") stroption = StrOption('str', 'Test string option', default="abc")
boolop = BoolOption('boolop', 'Test boolean option op', default=[True], multi=True) boolop = BoolOption('boolop', 'Test boolean option op', default=[True], multi=True)
wantref_option = BoolOption('wantref', 'Test requires', default=False, properties=('force_store_value',), hidden_property = Calculation(calc_value,
requires=({'option': booloption, 'expected': True, 'action': 'hidden'},)) Params(ParamValue('hidden'),
kwargs={'condition': ParamOption(booloption, raisepropertyerror=True),
'expected': ParamValue(True),
'default': ParamValue(None)}))
wantref_option = BoolOption('wantref', 'Test requires', default=False, properties=('force_store_value', hidden_property))
wantref2_option = BoolOption('wantref2', 'Test requires', default=False, properties=('force_store_value', 'hidden')) wantref2_option = BoolOption('wantref2', 'Test requires', default=False, properties=('force_store_value', 'hidden'))
wantref3_option = BoolOption('wantref3', 'Test requires', default=[False], multi=True, properties=('force_store_value',)) wantref3_option = BoolOption('wantref3', 'Test requires', default=[False], multi=True, properties=('force_store_value',))
st2 = SymLinkOption('st2', wantref3_option) st2 = SymLinkOption('st2', wantref3_option)
hidden_property = Calculation(calc_value,
Params(ParamValue('hidden'),
kwargs={'condition': ParamOption(booloption, raisepropertyerror=True),
'expected': ParamValue(True),
'default': ParamValue(None)}))
wantframework_option = BoolOption('wantframework', 'Test requires', wantframework_option = BoolOption('wantframework', 'Test requires',
default=False, default=False,
requires=({'option': booloption, 'expected': True, 'action': 'hidden'},)) properties=(hidden_property,))
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption]) gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
descr = OptionDescription('tiramisu', '', [gcgroup, booloption, objspaceoption, descr = OptionDescription('tiramisu', '', [gcgroup, booloption, objspaceoption,

View file

@ -6,7 +6,8 @@ do_autopath()
from py.test import raises from py.test import raises
from tiramisu import Config from tiramisu import Config
from tiramisu import IntOption, StrOption, UnicodeOption, OptionDescription, \ from tiramisu import IntOption, StrOption, UnicodeOption, OptionDescription, \
SymLinkOption, Leadership, undefined, Params, ParamOption SymLinkOption, Leadership, undefined, Calculation, Params, \
ParamOption, ParamValue, calc_value
from tiramisu.error import PropertiesOptionError, ConfigError from tiramisu.error import PropertiesOptionError, ConfigError
from tiramisu.setting import groups from tiramisu.setting import groups
from tiramisu.storage import list_sessions from tiramisu.storage import list_sessions
@ -575,7 +576,12 @@ def test_mandatory_warnings_requires():
properties=('mandatory', )) properties=('mandatory', ))
stroption2 = UnicodeOption('unicode2', 'Test string option', stroption2 = UnicodeOption('unicode2', 'Test string option',
properties=('mandatory', )) properties=('mandatory', ))
stroption3 = StrOption('str3', 'Test string option', multi=True, requires=[{'option': stroption, 'expected': 'yes', 'action': 'mandatory', 'transitive': False}]) mandatory_property = Calculation(calc_value,
Params(ParamValue('mandatory'),
kwargs={'condition': ParamOption(stroption, notraisepropertyerror=True),
'expected': ParamValue('yes'),
'no_condition_is_invalid': ParamValue(True)}))
stroption3 = StrOption('str3', 'Test string option', multi=True, properties=(mandatory_property,))
descr = OptionDescription('tiram', '', [stroption, stroption1, stroption2, stroption3]) descr = OptionDescription('tiram', '', [stroption, stroption1, stroption2, stroption3])
cfg = Config(descr) cfg = Config(descr)
cfg.option('str').value.set('') cfg.option('str').value.set('')
@ -593,7 +599,13 @@ def test_mandatory_warnings_requires_leadership():
stroption = StrOption('str', 'Test string option', default="abc", stroption = StrOption('str', 'Test string option', default="abc",
properties=('mandatory', )) properties=('mandatory', ))
stroption1 = StrOption('str1', 'Test string option', multi=True) stroption1 = StrOption('str1', 'Test string option', multi=True)
stroption2 = StrOption('str2', 'Test string option', multi=True, requires=[{'option': stroption, 'expected': 'yes', 'action': 'mandatory', 'transitive': False}]) mandatory_property = Calculation(calc_value,
Params(ParamValue(None),
kwargs={'condition': ParamOption(stroption),
'expected': ParamValue('yes'),
'inverse_condition': ParamValue(True),
'default': ParamValue('mandatory')}))
stroption2 = StrOption('str2', 'Test string option', multi=True, properties=(mandatory_property,))
leadership = Leadership('leader', 'leadership', [stroption1, stroption2]) leadership = Leadership('leader', 'leadership', [stroption1, stroption2])
descr = OptionDescription('tiram', '', [stroption, leadership]) descr = OptionDescription('tiram', '', [stroption, leadership])
cfg = Config(descr) cfg = Config(descr)
@ -607,7 +619,13 @@ def test_mandatory_warnings_requires_leadership():
def test_mandatory_warnings_requires_leadership_follower(): def test_mandatory_warnings_requires_leadership_follower():
stroption = StrOption('str', 'Test string option', multi=True) stroption = StrOption('str', 'Test string option', multi=True)
stroption1 = StrOption('str1', 'Test string option', multi=True) stroption1 = StrOption('str1', 'Test string option', multi=True)
stroption2 = StrOption('str2', 'Test string option', multi=True, requires=[{'option': stroption1, 'expected': 'yes', 'action': 'mandatory', 'transitive': False}]) mandatory_property = Calculation(calc_value,
Params(ParamValue(None),
kwargs={'condition': ParamOption(stroption1),
'expected': ParamValue('yes'),
'inverse_condition': ParamValue(True),
'default': ParamValue('mandatory')}))
stroption2 = StrOption('str2', 'Test string option', multi=True, properties=(mandatory_property,))
leadership = Leadership('leader', 'leadership', [stroption, stroption1, stroption2]) leadership = Leadership('leader', 'leadership', [stroption, stroption1, stroption2])
descr = OptionDescription('tiram', '', [leadership]) descr = OptionDescription('tiram', '', [leadership])
cfg = Config(descr) cfg = Config(descr)

View file

@ -5,7 +5,7 @@ do_autopath()
from tiramisu.setting import groups, owners from tiramisu.setting import groups, owners
from tiramisu import IntOption, StrOption, NetworkOption, NetmaskOption, BoolOption, ChoiceOption, \ from tiramisu import IntOption, StrOption, NetworkOption, NetmaskOption, BoolOption, ChoiceOption, \
IPOption, OptionDescription, Leadership, Config, GroupConfig, MetaConfig, \ IPOption, OptionDescription, Leadership, Config, GroupConfig, MetaConfig, \
Params, ParamOption, ParamValue Calculation, Params, ParamOption, ParamValue, calc_value
from tiramisu.error import ConfigError, ConflictError, PropertiesOptionError, LeadershipError, APIError from tiramisu.error import ConfigError, ConflictError, PropertiesOptionError, LeadershipError, APIError
from tiramisu.storage import list_sessions from tiramisu.storage import list_sessions
from .config import config_type, get_config from .config import config_type, get_config
@ -748,7 +748,11 @@ def test_meta_exception_meta():
def test_meta_properties_requires1(): def test_meta_properties_requires1():
opt1 = BoolOption('opt1', 'opt1', False) opt1 = BoolOption('opt1', 'opt1', False)
opt2 = BoolOption('opt2', "") opt2 = BoolOption('opt2', "")
od2 = OptionDescription('od2', "", [opt2], requires=({'option': opt1, 'expected': False, 'action': 'disabled'},)) disabled_property = Calculation(calc_value,
Params(ParamValue('disabled'),
kwargs={'condition': ParamOption(opt1, todict=True),
'expected': ParamValue(False)}))
od2 = OptionDescription('od2', "", [opt2], properties=(disabled_property,))
opt3 = BoolOption('opt3', '') opt3 = BoolOption('opt3', '')
opt2.impl_add_consistency('not_equal', opt3) opt2.impl_add_consistency('not_equal', opt3)
od = OptionDescription('root', '', [opt1, od2, opt3]) od = OptionDescription('root', '', [opt1, od2, opt3])
@ -765,7 +769,12 @@ def test_meta_properties_requires_mandatory():
probes = BoolOption('probes', 'probes available', False) probes = BoolOption('probes', 'probes available', False)
eth0_method = ChoiceOption('eth0_method', '', ('static', 'dhcp'), 'static') eth0_method = ChoiceOption('eth0_method', '', ('static', 'dhcp'), 'static')
ip_address = IPOption('ip_address', '') ip_address = IPOption('ip_address', '')
ip_eth0 = IPOption('ip_eth0', "ip", requires=({'option': probes, 'expected': True, 'action': 'mandatory'},), callback=return_condition, callback_params=Params(kwargs={'val': ParamOption(ip_address), 'condition': ParamOption(eth0_method), 'expected': ParamValue('dhcp')})) mandatory_property = Calculation(calc_value,
Params(ParamValue('mandatory'),
kwargs={'condition': ParamOption(probes),
'expected': ParamValue('yes'),
'default': ParamValue(None)}))
ip_eth0 = IPOption('ip_eth0', "ip", properties=(mandatory_property,), callback=return_condition, callback_params=Params(kwargs={'val': ParamOption(ip_address), 'condition': ParamOption(eth0_method), 'expected': ParamValue('dhcp')}))
ip_gw = IPOption('ip_gw', 'gw') ip_gw = IPOption('ip_gw', 'gw')
ip_gw.impl_add_consistency('not_equal', ip_eth0) ip_gw.impl_add_consistency('not_equal', ip_eth0)
od = OptionDescription('root', '', [ip_gw, probes, eth0_method, ip_address, ip_eth0]) od = OptionDescription('root', '', [ip_gw, probes, eth0_method, ip_address, ip_eth0])

View file

@ -3,13 +3,14 @@ do_autopath()
from .config import config_type, get_config from .config import config_type, get_config
from py.test import raises from py.test import raises
import warnings
from tiramisu import Config from tiramisu import Config
from tiramisu.config import KernelConfig from tiramisu.config import KernelConfig
from tiramisu.setting import groups, owners from tiramisu.setting import groups, owners
from tiramisu import ChoiceOption, BoolOption, IntOption, FloatOption, \ from tiramisu import ChoiceOption, BoolOption, IntOption, FloatOption, \
StrOption, OptionDescription, SymLinkOption, IPOption, NetmaskOption, Leadership, \ StrOption, OptionDescription, SymLinkOption, IPOption, NetmaskOption, Leadership, \
undefined, Params, ParamOption, ParamValue, ParamContext, calc_value undefined, Calculation, Params, ParamOption, ParamValue, ParamContext, calc_value
from tiramisu.error import PropertiesOptionError, ConflictError, LeadershipError, ConfigError from tiramisu.error import PropertiesOptionError, ConflictError, LeadershipError, ConfigError
from tiramisu.i18n import _ from tiramisu.i18n import _
from tiramisu.storage import list_sessions from tiramisu.storage import list_sessions
@ -102,11 +103,9 @@ def make_description_duplicates():
floatoption = FloatOption('float', 'Test float option', default=2.3) floatoption = FloatOption('float', 'Test float option', default=2.3)
stroption = StrOption('str', 'Test string option', default="abc") stroption = StrOption('str', 'Test string option', default="abc")
boolop = BoolOption('boolop', 'Test boolean option op', default=True) boolop = BoolOption('boolop', 'Test boolean option op', default=True)
wantref_option = BoolOption('wantref', 'Test requires', default=False, wantref_option = BoolOption('wantref', 'Test requires', default=False)
requires=({'option': boolop, 'expected': True, 'action': 'hidden'},))
wantframework_option = BoolOption('wantframework', 'Test requires', wantframework_option = BoolOption('wantframework', 'Test requires',
default=False, default=False)
requires=({'option': boolop, 'expected': True, 'action': 'hidden'},))
# dummy2 (same path) # dummy2 (same path)
gcdummy2 = BoolOption('dummy', 'dummy2', default=True) gcdummy2 = BoolOption('dummy', 'dummy2', default=True)
# dummy3 (same name) # dummy3 (same name)
@ -123,13 +122,18 @@ def test_identical_paths():
"""If in the schema (the option description) there is something that """If in the schema (the option description) there is something that
have the same name, an exection is raised have the same name, an exection is raised
""" """
with warnings.catch_warnings(record=True) as w:
raises(ConflictError, "make_description_duplicates()") raises(ConflictError, "make_description_duplicates()")
def test_hidden_if_in2(config_type): def test_hidden_if_in2(config_type):
intoption = IntOption('int', 'Test int option', default=0) intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default="abc", hidden_property = Calculation(calc_value,
requires=({'option': intoption, 'expected': 1, 'action': 'hidden'},)) Params(ParamValue('hidden'),
kwargs={'condition': ParamOption(intoption),
'expected': ParamValue(1),
'default': ParamValue(None)}))
stroption = StrOption('str', 'Test string option', default="abc", properties=(hidden_property,))
descr = OptionDescription('constraints', '', [stroption, intoption]) descr = OptionDescription('constraints', '', [stroption, intoption])
cfg_ori = Config(descr) cfg_ori = Config(descr)
cfg_ori.property.read_write() cfg_ori.property.read_write()
@ -154,8 +158,12 @@ def test_hidden_if_in_with_group(config_type):
booloption = BoolOption('bool', 'Test boolean option', default=True) booloption = BoolOption('bool', 'Test boolean option', default=True)
intoption = IntOption('int', 'Test int option', default=0) intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default="abc") stroption = StrOption('str', 'Test string option', default="abc")
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption], hidden_property = Calculation(calc_value,
requires=({'option': intoption, 'expected': 1, 'action': 'hidden'},)) Params(ParamValue('hidden'),
kwargs={'condition': ParamOption(intoption),
'expected': ParamValue(1),
'default': ParamValue(None)}))
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption], properties=(hidden_property,))
descr = OptionDescription('constraints', '', [gcgroup, booloption, descr = OptionDescription('constraints', '', [gcgroup, booloption,
objspaceoption, stroption, intoption]) objspaceoption, stroption, intoption])
cfg_ori = Config(descr) cfg_ori = Config(descr)
@ -179,8 +187,12 @@ def test_disabled_with_group():
booloption = BoolOption('bool', 'Test boolean option', default=True) booloption = BoolOption('bool', 'Test boolean option', default=True)
intoption = IntOption('int', 'Test int option', default=0) intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default="abc") stroption = StrOption('str', 'Test string option', default="abc")
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption], disabled_property = Calculation(calc_value,
requires=({'option': intoption, 'expected': 1, 'action': 'disabled'},)) Params(ParamValue('disabled'),
kwargs={'condition': ParamOption(intoption),
'expected': ParamValue(1),
'default': ParamValue(None)}))
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption], properties=(disabled_property,))
descr = OptionDescription('constraints', '', [gcgroup, booloption, descr = OptionDescription('constraints', '', [gcgroup, booloption,
objspaceoption, stroption, intoption]) objspaceoption, stroption, intoption])
cfg = Config(descr) cfg = Config(descr)
@ -201,11 +213,15 @@ def make_description_callback():
floatoption = FloatOption('float', 'Test float option', default=2.3) floatoption = FloatOption('float', 'Test float option', default=2.3)
stroption = StrOption('str', 'Test string option', default="abc") stroption = StrOption('str', 'Test string option', default="abc")
boolop = BoolOption('boolop', 'Test boolean option op', default=True) boolop = BoolOption('boolop', 'Test boolean option op', default=True)
wantref_option = BoolOption('wantref', 'Test requires', default=False, hidden_property = Calculation(calc_value,
requires=({'option': boolop, 'expected': True, 'action': 'hidden'},)) Params(ParamValue('hidden'),
kwargs={'condition': ParamOption(boolop),
'expected': ParamValue(True),
'default': ParamValue(None)}))
wantref_option = BoolOption('wantref', 'Test requires', default=False, properties=(hidden_property,))
wantframework_option = BoolOption('wantframework', 'Test requires', wantframework_option = BoolOption('wantframework', 'Test requires',
default=False, default=False,
requires=({'option': boolop, 'expected': True, 'action': 'hidden'},)) properties=(hidden_property,))
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption]) gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption, descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
wantref_option, stroption, wantref_option, stroption,
@ -268,7 +284,7 @@ def test_params():
def test_param_option(): def test_param_option():
val1 = StrOption('val1', "") val1 = StrOption('val1', "")
raises(ValueError, "ParamOption('str')") raises(ValueError, "ParamOption('str')")
raises(ValueError, "ParamOption(val1, 'str')") raises(AssertionError, "ParamOption(val1, 'str')")
def test_callback_invalid(): def test_callback_invalid():

View file

@ -9,7 +9,8 @@ from tiramisu.i18n import _
from tiramisu.error import display_list, ConfigError from tiramisu.error import display_list, ConfigError
from tiramisu.setting import owners, groups from tiramisu.setting import owners, groups
from tiramisu import ChoiceOption, BoolOption, IntOption, FloatOption, \ from tiramisu import ChoiceOption, BoolOption, IntOption, FloatOption, \
StrOption, OptionDescription, Leadership, Config, undefined StrOption, OptionDescription, Leadership, Config, undefined, \
Calculation, Params, ParamOption, ParamValue, ParamIndex, calc_value, calc_value_property_help
from tiramisu.error import PropertiesOptionError from tiramisu.error import PropertiesOptionError
from tiramisu.storage import list_sessions from tiramisu.storage import list_sessions
@ -168,8 +169,11 @@ def test_reset_with_multi(config_type):
def test_property_only_raises(): def test_property_only_raises():
s = StrOption("string", "", default=["string"], default_multi="string", multi=True) s = StrOption("string", "", default=["string"], default_multi="string", multi=True)
intoption = IntOption('int', 'Test int option', default=0) intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default=["abc"], default_multi="abc", hidden_property = Calculation(calc_value,
requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}], multi=True) Params(ParamValue('hidden'),
kwargs={'condition': ParamOption(intoption),
'expected': ParamValue(1)}))
stroption = StrOption('str', 'Test string option', default=["abc"], default_multi="abc", properties=(hidden_property,), multi=True)
descr = OptionDescription("options", "", [s, intoption, stroption]) descr = OptionDescription("options", "", [s, intoption, stroption])
cfg = Config(descr) cfg = Config(descr)
cfg.property.read_write() cfg.property.read_write()
@ -231,8 +235,11 @@ def test_access_with_multi_default(config_type):
def test_multi_with_requires(): def test_multi_with_requires():
s = StrOption("string", "", default=["string"], default_multi="string", multi=True) s = StrOption("string", "", default=["string"], default_multi="string", multi=True)
intoption = IntOption('int', 'Test int option', default=0) intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default=["abc"], default_multi="abc", hidden_property = Calculation(calc_value,
requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}], multi=True) Params(ParamValue('hidden'),
kwargs={'condition': ParamOption(intoption),
'expected': ParamValue(1)}))
stroption = StrOption('str', 'Test string option', default=["abc"], default_multi="abc", properties=(hidden_property,), multi=True)
descr = OptionDescription("options", "", [s, intoption, stroption]) descr = OptionDescription("options", "", [s, intoption, stroption])
cfg = Config(descr) cfg = Config(descr)
cfg.property.read_write() cfg.property.read_write()
@ -242,23 +249,32 @@ def test_multi_with_requires():
assert 'hidden' in cfg.forcepermissive.option('str').property.get() assert 'hidden' in cfg.forcepermissive.option('str').property.get()
def test__requires_with_inverted(): def test_requires_with_inverted():
s = StrOption("string", "", default=["string"], multi=True) s = StrOption("string", "", default=["string"], multi=True)
intoption = IntOption('int', 'Test int option', default=0) intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default=["abc"], default_multi="abc", hide_property = Calculation(calc_value,
requires=[{'option': intoption, 'expected': 1, 'action': 'hide', 'inverse': True}], multi=True) Params(ParamValue('hide'),
kwargs={'condition': ParamOption(intoption),
'expected': ParamValue(1),
'inverse_condition': ParamValue(True)}))
stroption = StrOption('str', 'Test string option', default=["abc"], default_multi="abc", properties=(hide_property,), multi=True)
descr = OptionDescription("options", "", [s, intoption, stroption]) descr = OptionDescription("options", "", [s, intoption, stroption])
cfg = Config(descr) cfg = Config(descr)
assert not 'hidden' in cfg.option('str').property.get() assert not 'hidden' in cfg.option('str').property.get()
assert 'hide' in cfg.option('str').property.get()
cfg.option('int').value.set(1) cfg.option('int').value.set(1)
assert not 'hidden' in cfg.option('str').property.get() assert not 'hidden' in cfg.option('str').property.get()
assert not 'hide' in cfg.option('str').property.get()
def test_multi_with_requires_in_another_group(): def test_multi_with_requires_in_another_group():
s = StrOption("string", "", default=["string"], multi=True) s = StrOption("string", "", default=["string"], multi=True)
intoption = IntOption('int', 'Test int option', default=0) intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default=["abc"], hidden_property = Calculation(calc_value,
requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}], multi=True) Params(ParamValue('hidden'),
kwargs={'condition': ParamOption(intoption),
'expected': ParamValue(1)}))
stroption = StrOption('str', 'Test string option', default=["abc"], properties=(hidden_property,), multi=True)
descr = OptionDescription("opt", "", [stroption]) descr = OptionDescription("opt", "", [stroption])
descr2 = OptionDescription("opt2", "", [intoption, s, descr]) descr2 = OptionDescription("opt2", "", [intoption, s, descr])
cfg = Config(descr2) cfg = Config(descr2)
@ -272,8 +288,12 @@ def test_multi_with_requires_in_another_group():
def test_multi_with_requires_in_another_group_inverse(): def test_multi_with_requires_in_another_group_inverse():
s = StrOption("string", "", default=["string"], multi=True) s = StrOption("string", "", default=["string"], multi=True)
intoption = IntOption('int', 'Test int option', default=0) intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default=["abc"], hidden_property = Calculation(calc_value,
requires=[{'option': intoption, 'expected': 0, 'action': 'hidden', 'inverse': True}], multi=True) Params(ParamValue('hidden'),
kwargs={'condition': ParamOption(intoption),
'expected': ParamValue(1)}))
# requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}], multi=True)
stroption = StrOption('str', 'Test string option', default=["abc"], properties=(hidden_property,), multi=True)
descr = OptionDescription("opt", "", [stroption]) descr = OptionDescription("opt", "", [stroption])
descr2 = OptionDescription("opt2", "", [intoption, s, descr]) descr2 = OptionDescription("opt2", "", [intoption, s, descr])
cfg = Config(descr2) cfg = Config(descr2)
@ -287,8 +307,11 @@ def test_multi_with_requires_in_another_group_inverse():
def test_apply_requires_from_config(): def test_apply_requires_from_config():
s = StrOption("string", "", default=["string"], multi=True) s = StrOption("string", "", default=["string"], multi=True)
intoption = IntOption('int', 'Test int option', default=0) intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default=["abc"], hidden_property = Calculation(calc_value,
requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}], multi=True) Params(ParamValue('hidden'),
kwargs={'condition': ParamOption(intoption),
'expected': ParamValue(1)}))
stroption = StrOption('str', 'Test string option', default=["abc"], properties=(hidden_property,), multi=True)
descr = OptionDescription("opt", "", [stroption]) descr = OptionDescription("opt", "", [stroption])
descr2 = OptionDescription("opt2", "", [intoption, s, descr]) descr2 = OptionDescription("opt2", "", [intoption, s, descr])
cfg = Config(descr2) cfg = Config(descr2)
@ -304,8 +327,11 @@ def test_apply_requires_from_config():
def test_apply_requires_with_disabled(): def test_apply_requires_with_disabled():
s = StrOption("string", "", default=["string"], multi=True) s = StrOption("string", "", default=["string"], multi=True)
intoption = IntOption('int', 'Test int option', default=0) intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default=["abc"], disabled_property = Calculation(calc_value,
requires=[{'option': intoption, 'expected': 1, 'action': 'disabled'}], multi=True) Params(ParamValue('disabled'),
kwargs={'condition': ParamOption(intoption),
'expected': ParamValue(1)}))
stroption = StrOption('str', 'Test string option', default=["abc"], properties=(disabled_property,), multi=True)
descr = OptionDescription("opt", "", [stroption]) descr = OptionDescription("opt", "", [stroption])
descr2 = OptionDescription("opt2", "", [intoption, s, descr]) descr2 = OptionDescription("opt2", "", [intoption, s, descr])
cfg = Config(descr2) cfg = Config(descr2)
@ -321,8 +347,11 @@ def test_apply_requires_with_disabled():
def test_multi_with_requires_with_disabled_in_another_group(): def test_multi_with_requires_with_disabled_in_another_group():
s = StrOption("string", "", default=["string"], multi=True) s = StrOption("string", "", default=["string"], multi=True)
intoption = IntOption('int', 'Test int option', default=0) intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default=["abc"], disabled_property = Calculation(calc_value,
requires=[{'option': intoption, 'expected': 1, 'action': 'disabled'}], multi=True) Params(ParamValue('disabled'),
kwargs={'condition': ParamOption(intoption),
'expected': ParamValue(1)}))
stroption = StrOption('str', 'Test string option', default=["abc"], properties=(disabled_property,), multi=True)
descr = OptionDescription("opt", "", [stroption]) descr = OptionDescription("opt", "", [stroption])
descr2 = OptionDescription("opt2", "", [intoption, s, descr]) descr2 = OptionDescription("opt2", "", [intoption, s, descr])
cfg = Config(descr2) cfg = Config(descr2)
@ -331,42 +360,54 @@ def test_multi_with_requires_with_disabled_in_another_group():
cfg.option('int').value.set(1) cfg.option('int').value.set(1)
raises(PropertiesOptionError, "cfg.option('opt.str').value.set(['a', 'b'])") raises(PropertiesOptionError, "cfg.option('opt.str').value.set(['a', 'b'])")
assert 'disabled' in cfg.unrestraint.option('opt.str').property.get() assert 'disabled' in cfg.unrestraint.option('opt.str').property.get()
#
#
def test_multi_with_requires_that_is_multi(): #def test_multi_with_requires_that_is_multi():
b = IntOption('int', 'Test int option', default=[0], multi=True) # b = IntOption('int', 'Test int option', default=[0], multi=True)
c = StrOption('str', 'Test string option', default=['abc'], requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True) # hidden_property = Calculation(calc_value,
descr = OptionDescription("opt", "", [b, c]) # Params(ParamValue('hidden'),
descr # kwargs={'condition': ParamOption(b),
raises(ValueError, "Config(descr)") # 'expected': ParamValue(1)}))
# c = StrOption('str', 'Test string option', default=['abc'], properties=(hidden_property,), multi=True)
# descr = OptionDescription("opt", "", [b, c])
def test_multi_with_requires_that_is_multi_inverse(): # descr
b = IntOption('int', 'Test int option', default=[0], multi=True) # # FIXME: ValueError: requirement mal formés pour l'option "int" ne doit pas être une valeur multiple pour "str"
c = StrOption('str', 'Test string option', default=['abc'], requires=[{'option': b, 'expected': 0, 'action': 'hidden', 'inverse': True}], multi=True) # raises(ValueError, "Config(descr)")
descr = OptionDescription("opt", "", [b, c]) #
descr #
raises(ValueError, "Config(descr)") #def test_multi_with_requires_that_is_multi_inverse():
# b = IntOption('int', 'Test int option', default=[0], multi=True)
# c = StrOption('str', 'Test string option', default=['abc'], requires=[{'option': b, 'expected': 0, 'action': 'hidden', 'inverse': True}], multi=True)
def test_multi_with_requires_that_is_leadership(): # descr = OptionDescription("opt", "", [b, c])
b = IntOption('int', 'Test int option', default=[0], multi=True) # descr
c = StrOption('str', 'Test string option', requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True) # Config(descr)
descr = Leadership("int", "", [b, c]) # # FIXME: ValueError: requirement mal formés pour l'option "int" ne doit pas être une valeur multiple pour "str"
od = OptionDescription('root', '', [descr]) # raises(ValueError, "Config(descr)")
Config(od) #
#
#def test_multi_with_requires_that_is_leadership():
def test_multi_with_requires_that_is_leadership_leader(): # b = IntOption('int', 'Test int option', default=[0], multi=True)
b = IntOption('int', 'Test int option', multi=True) # c = StrOption('str', 'Test string option', requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True)
c = StrOption('str', 'Test string option', requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True) # descr = Leadership("int", "", [b, c])
raises(ValueError, "Leadership('str', '', [c, b])") # od = OptionDescription('root', '', [descr])
# Config(od)
#
#
#def test_multi_with_requires_that_is_leadership_leader():
# b = IntOption('int', 'Test int option', multi=True)
# c = StrOption('str', 'Test string option', requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True)
# raises(ValueError, "Leadership('str', '', [c, b])")
def test_multi_with_requires_that_is_leadership_follower(): def test_multi_with_requires_that_is_leadership_follower():
b = IntOption('int', 'Test int option', default=[0], multi=True) b = IntOption('int', 'Test int option', default=[0], multi=True)
c = StrOption('str', 'Test string option', multi=True) c = StrOption('str', 'Test string option', multi=True)
d = StrOption('str1', 'Test string option', requires=[{'option': c, 'expected': '1', 'action': 'hidden'}], multi=True) hidden_property = Calculation(calc_value,
Params(ParamValue('hidden'),
kwargs={'condition': ParamOption(c),
'index': ParamIndex(),
'expected': ParamValue('1')}))
d = StrOption('str1', 'Test string option', properties=(hidden_property,), multi=True)
descr = Leadership("int", "", [b, c, d]) descr = Leadership("int", "", [b, c, d])
descr2 = OptionDescription('od', '', [descr]) descr2 = OptionDescription('od', '', [descr])
cfg = Config(descr2) cfg = Config(descr2)
@ -392,7 +433,13 @@ def test_multi_with_requires_that_is_leadership_follower():
def test_multi_with_requires_that_is_leadership_follower_inverse(): def test_multi_with_requires_that_is_leadership_follower_inverse():
b = IntOption('int', 'Test int option', default=[0], multi=True) b = IntOption('int', 'Test int option', default=[0], multi=True)
c = StrOption('str', 'Test string option', multi=True) c = StrOption('str', 'Test string option', multi=True)
d = StrOption('str1', 'Test string option', requires=[{'option': c, 'expected': None, 'action': 'hidden', 'inverse': True}], multi=True) hidden_property = Calculation(calc_value,
Params(ParamValue('hidden'),
kwargs={'condition': ParamOption(c),
'index': ParamIndex(),
'inverse_condition': ParamValue(True),
'expected': ParamValue(None)}))
d = StrOption('str1', 'Test string option', properties=(hidden_property,), multi=True)
descr = Leadership("int", "", [b, c, d]) descr = Leadership("int", "", [b, c, d])
descr2 = OptionDescription('od', '', [descr]) descr2 = OptionDescription('od', '', [descr])
cfg = Config(descr2) cfg = Config(descr2)
@ -415,16 +462,22 @@ def test_multi_with_requires_that_is_leadership_follower_inverse():
raises(PropertiesOptionError, "cfg.option('int.str1', 1).value.get()") raises(PropertiesOptionError, "cfg.option('int.str1', 1).value.get()")
def test_multi_with_requires_that_is_not_same_leadership(): #def test_multi_with_requires_that_is_not_same_leadership():
b = IntOption('int', 'Test int option', default=[0], multi=True) # b = IntOption('int', 'Test int option', default=[0], multi=True)
c = StrOption('str', 'Test string option', requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True) # hidden_property = Calculation(calc_value,
descr1 = Leadership("int", "", [b, c]) # Params(ParamValue('hidden'),
d = IntOption('int1', 'Test int option', default=[0], multi=True) # kwargs={'condition': ParamOption(b),
e = StrOption('str', 'Test string option', requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True) # 'index': ParamIndex(),
descr2 = Leadership("int1", "", [d, e]) # 'expected': ParamValue(1)}))
descr3 = OptionDescription('val', '', [descr1, descr2]) # c = StrOption('str', 'Test string option', properties=(hidden_property,), multi=True)
descr3 # #c = StrOption('str', 'Test string option', requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True)
raises(ValueError, "Config(descr3)") # descr1 = Leadership("int", "", [b, c])
# d = IntOption('int1', 'Test int option', default=[0], multi=True)
# e = StrOption('str', 'Test string option', requires=[{'option': b, 'expected': 1, 'action': 'hidden'}], multi=True)
# descr2 = Leadership("int1", "", [d, e])
# descr3 = OptionDescription('val', '', [descr1, descr2])
# descr3
# raises(ValueError, "Config(descr3)")
def test_multi_with_bool(): def test_multi_with_bool():
@ -606,17 +659,45 @@ def test_pprint():
s2 = StrOption("string2", "", default="string") s2 = StrOption("string2", "", default="string")
s3 = StrOption("string3", "", default=["string"], default_multi="string", multi=True, properties=('hidden',)) s3 = StrOption("string3", "", default=["string"], default_multi="string", multi=True, properties=('hidden',))
intoption = IntOption('int', 'Test int option', default=0) intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default="abc", hidden_property = Calculation(calc_value,
requires=[{'option': intoption, 'expected': 2, 'action': 'hidden', 'inverse': True}, Params(ParamValue('hidden'),
{'option': intoption, 'expected': 3, 'action': 'hidden', 'inverse': True}, kwargs={'condition': ParamOption(intoption, todict=True),
{'option': intoption, 'expected': 4, 'action': 'hidden', 'inverse': True}, 'expected_0': ParamValue(2),
{'option': intoption, 'expected': 1, 'action': 'disabled'}, 'expected_1': ParamValue(3),
{'option': s2, 'expected': 'string', 'action': 'disabled'}]) 'expected_2': ParamValue(4),
'inverse_condition': ParamValue(True)}),
calc_value_property_help)
disabled_property = Calculation(calc_value,
Params(ParamValue('disabled'),
kwargs={'condition_0': ParamOption(intoption, todict=True),
'expected_0': ParamValue(1),
'condition_1': ParamOption(s2, todict=True),
'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', "") val2 = StrOption('val2', "")
descr2 = OptionDescription("options", "", [val2], requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}]) hidden_property = Calculation(calc_value,
Params(ParamValue('hidden'),
kwargs={'condition': ParamOption(intoption, todict=True),
'expected': ParamValue(1)}),
calc_value_property_help)
descr2 = OptionDescription("options", "", [val2], properties=(hidden_property,))
#descr2 = OptionDescription("options", "", [val2], requires=[{'option': intoption, 'expected': 1, 'action': 'hidden'}])
val3 = StrOption('val3', "", requires=[{'option': stroption, 'expected': '2', 'action': 'hidden', 'inverse': True}]) hidden_property = Calculation(calc_value,
Params(ParamValue('hidden'),
kwargs={'condition': ParamOption(stroption, todict=True),
'expected': ParamValue('2'),
'inverse_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}])
descr = OptionDescription("options", "", [s, s2, s3, intoption, stroption, descr2, val3]) descr = OptionDescription("options", "", [s, s2, s3, intoption, stroption, descr2, val3])
cfg = Config(descr) cfg = Config(descr)

View file

@ -7,7 +7,8 @@ from .config import config_type, get_config
from py.test import raises from py.test import raises
from tiramisu import ChoiceOption, BoolOption, IntOption, FloatOption, \ from tiramisu import ChoiceOption, BoolOption, IntOption, FloatOption, \
PasswordOption, StrOption, DateOption, OptionDescription, Config PasswordOption, StrOption, DateOption, OptionDescription, Config, \
Calculation, Params, ParamOption, ParamValue, calc_value
from tiramisu.error import PropertiesOptionError from tiramisu.error import PropertiesOptionError
from tiramisu.storage import list_sessions from tiramisu.storage import list_sessions
@ -26,11 +27,17 @@ def make_description():
floatoption = FloatOption('float', 'Test float option', default=2.3) floatoption = FloatOption('float', 'Test float option', default=2.3)
stroption = StrOption('str', 'Test string option', default="abc") stroption = StrOption('str', 'Test string option', default="abc")
wantref_option = BoolOption('wantref', 'Test requires', default=False, hidden_property = Calculation(calc_value,
requires=({'option': gcoption, 'expected': 'ref', 'action': 'hidden'},)) Params(ParamValue('hidden'),
kwargs={'condition': ParamOption(gcoption),
'expected': ParamValue('ref')}))
wantref_option = BoolOption('wantref', 'Test requires', default=False, properties=(hidden_property,))
hidden_property = Calculation(calc_value,
Params(ParamValue('hidden'),
kwargs={'condition': ParamOption(gcoption),
'expected': ParamValue('framework')}))
wantframework_option = BoolOption('wantframework', 'Test requires', wantframework_option = BoolOption('wantframework', 'Test requires',
default=False, default=False, properties=(hidden_property,))
requires=({'option': gcoption, 'expected': 'framework', 'action': 'hidden'},))
# ____________________________________________________________ # ____________________________________________________________
booloptiontwo = BoolOption('booltwo', 'Test boolean option two', default=False) booloptiontwo = BoolOption('booltwo', 'Test boolean option two', default=False)

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,8 @@
#from autopath import do_autopath #from autopath import do_autopath
#do_autopath() #do_autopath()
# #
from tiramisu.option import BoolOption, UnicodeOption, SymLinkOption, \ from tiramisu import BoolOption, UnicodeOption, SymLinkOption, OptionDescription, DynOptionDescription, \
OptionDescription, DynOptionDescription Calculation, Params, ParamOption, ParamValue, calc_value, Config
from tiramisu import Config
from pickle import dumps from pickle import dumps
from py.test import raises from py.test import raises
import sys import sys
@ -213,7 +212,12 @@ def _diff_conf(cfg1, cfg2):
def test_diff_opt(): def test_diff_opt():
b = BoolOption('b', '') b = BoolOption('b', '')
u = UnicodeOption('u', '', requires=[{'option': b, 'expected': True, 'action': 'disabled', 'inverse': True}]) disabled_property = Calculation(calc_value,
Params(ParamValue('disabled'),
kwargs={'condition': ParamOption(b),
'expected': ParamValue(True),
'inverse_condition': ParamValue(True)}))
u = UnicodeOption('u', '', properties=(disabled_property,))
s = SymLinkOption('s', u) s = SymLinkOption('s', u)
o = OptionDescription('o', '', [b, u, s]) o = OptionDescription('o', '', [b, u, s])
o1 = OptionDescription('o1', '', [o]) o1 = OptionDescription('o1', '', [o])

View file

@ -5,7 +5,7 @@ do_autopath()
from .config import config_type, get_config from .config import config_type, get_config
from tiramisu import BoolOption, StrOption, SymLinkOption, \ from tiramisu import BoolOption, StrOption, SymLinkOption, \
OptionDescription, Leadership, Config OptionDescription, Leadership, Config, Calculation, calc_value, Params, ParamOption, ParamValue
from tiramisu.error import PropertiesOptionError, ConfigError from tiramisu.error import PropertiesOptionError, ConfigError
from tiramisu.setting import groups, owners from tiramisu.setting import groups, owners
from tiramisu.storage import list_sessions from tiramisu.storage import list_sessions
@ -122,9 +122,11 @@ def test_symlink_getcallback():
def test_symlink_requires(config_type): def test_symlink_requires(config_type):
boolopt = BoolOption('b', '', default=True) boolopt = BoolOption('b', '', default=True)
stropt = StrOption('s', '', requires=[{'option': boolopt, disabled_property = Calculation(calc_value,
'expected': False, Params(ParamValue('disabled'),
'action': 'disabled'}]) kwargs={'condition': ParamOption(boolopt),
'expected': ParamValue(False)}))
stropt = StrOption('s', '', properties=(disabled_property,))
linkopt = SymLinkOption("c", stropt) linkopt = SymLinkOption("c", stropt)
descr = OptionDescription('opt', '', [boolopt, stropt, linkopt]) descr = OptionDescription('opt', '', [boolopt, stropt, linkopt])
cfg = Config(descr) cfg = Config(descr)

View file

@ -14,8 +14,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Configuration management library written in python """Configuration management library written in python
""" """
from .function import Params, ParamOption, ParamValue, ParamContext, \ from .function import tiramisu_copy, calc_value, calc_value_property_help
tiramisu_copy, calc_value from .autolib import Calculation, Params, ParamOption, ParamSelfOption, ParamValue, ParamIndex, ParamContext
from .option import * from .option import *
from .error import APIError from .error import APIError
from .api import Config, MetaConfig, GroupConfig, MixConfig from .api import Config, MetaConfig, GroupConfig, MixConfig
@ -25,9 +25,12 @@ from .storage import default_storage, Storage, list_sessions, \
delete_session delete_session
allfuncs = ['Params', allfuncs = ['Calculation',
'Params',
'ParamOption', 'ParamOption',
'ParamSelfOption',
'ParamValue', 'ParamValue',
'ParamIndex',
'ParamContext', 'ParamContext',
'MetaConfig', 'MetaConfig',
'MixConfig', 'MixConfig',
@ -40,7 +43,8 @@ allfuncs = ['Params',
'list_sessions', 'list_sessions',
'delete_session', 'delete_session',
'tiramisu_copy', 'tiramisu_copy',
'calc_value'] 'calc_value',
'calc_value_property_help']
allfuncs.extend(all_options) allfuncs.extend(all_options)
del(all_options) del(all_options)
__all__ = tuple(allfuncs) __all__ = tuple(allfuncs)

View file

@ -384,8 +384,6 @@ class TiramisuOptionProperty(CommonTiramisuOption):
def get(self, def get(self,
only_raises=False): only_raises=False):
"""Get properties for an option""" """Get properties for an option"""
option = self._option_bag.option
#self._test_follower_index()
if not only_raises: if not only_raises:
return self._option_bag.properties return self._option_bag.properties
# do not check cache properties/permissives which are not save (unrestraint, ...) # do not check cache properties/permissives which are not save (unrestraint, ...)
@ -397,8 +395,8 @@ class TiramisuOptionProperty(CommonTiramisuOption):
if prop in FORBIDDEN_SET_PROPERTIES: if prop in FORBIDDEN_SET_PROPERTIES:
raise ConfigError(_('cannot add this property: "{0}"').format( raise ConfigError(_('cannot add this property: "{0}"').format(
' '.join(prop))) ' '.join(prop)))
props = self._settings.getproperties(self._option_bag, props = self._settings._p_.getproperties(self._option_bag.path,
apply_requires=False) option.impl_getproperties())
self._settings.setproperties(self._option_bag.path, self._settings.setproperties(self._option_bag.path,
props | {prop}, props | {prop},
self._option_bag, self._option_bag,
@ -407,8 +405,8 @@ class TiramisuOptionProperty(CommonTiramisuOption):
def pop(self, prop): def pop(self, prop):
"""Remove new property for an option""" """Remove new property for an option"""
option = self._option_bag.option option = self._option_bag.option
props = self._settings.getproperties(self._option_bag, props = self._settings._p_.getproperties(self._option_bag.path,
apply_requires=False) option.impl_getproperties())
self._settings.setproperties(self._option_bag.path, self._settings.setproperties(self._option_bag.path,
props - {prop}, props - {prop},
self._option_bag, self._option_bag,

View file

@ -19,22 +19,159 @@
# ____________________________________________________________ # ____________________________________________________________
"enables us to carry out a calculation and return an option's value" "enables us to carry out a calculation and return an option's value"
from typing import Any, Optional, Union, Callable, Dict, List from typing import Any, Optional, Union, Callable, Dict, List
from itertools import chain
from .error import PropertiesOptionError, ConfigError, LeadershipError from .error import PropertiesOptionError, ConfigError, LeadershipError
from .i18n import _ from .i18n import _
from .setting import undefined, ConfigBag, OptionBag, Undefined from .setting import undefined, ConfigBag, OptionBag, Undefined
from .storage import get_default_values_storages, get_default_settings_storages from .storage import get_default_values_storages, get_default_settings_storages
from .function import ParamValue, ParamContext, ParamIndex, ParamOption, Params
# ____________________________________________________________ # ____________________________________________________________
class Params:
__slots__ = ('args', 'kwargs')
def __init__(self, args=None, kwargs=None, **kwgs):
if args is None:
args = tuple()
if kwargs is None:
kwargs = {}
if kwgs:
kwargs.update(kwgs)
if isinstance(args, Param):
args = (args,)
else:
if not isinstance(args, tuple):
raise ValueError(_('args in params must be a tuple'))
for arg in args:
if not isinstance(arg, Param):
raise ValueError(_('arg in params must be a Param'))
if not isinstance(kwargs, dict):
raise ValueError(_('kwargs in params must be a dict'))
for arg in kwargs.values():
if not isinstance(arg, Param):
raise ValueError(_('arg in params must be a Param'))
self.args = args
self.kwargs = kwargs
class Param:
pass
class ParamOption(Param):
__slots__ = ('todict',
'error',
'option',
'notraisepropertyerror',
'raisepropertyerror')
def __init__(self,
option: 'Option',
notraisepropertyerror: bool=False,
raisepropertyerror: bool=False,
todict: bool=False) -> 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():
cur_opt = option.impl_getopt()
else:
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
class ParamSelfOption(Param):
__slots__ = ('todict',)
def __init__(self,
todict: bool=False) -> None:
self.todict = todict
class ParamValue(Param):
__slots__ = ('value',)
def __init__(self, value):
self.value = value
class ParamContext(Param):
__slots__ = tuple()
class ParamIndex(Param):
__slots__ = tuple()
class Calculation:
__slots__ = ('function',
'params',
'help_function',
'has_index')
def __init__(self,
function: Callable,
params: Optional[Params]=None,
help_function: Optional[Callable]=None):
assert isinstance(function, Callable), _('first argument ({0}) must be a function').format(function)
if help_function:
assert isinstance(help_function, Callable), _('help_function ({0}) must be a function').format(help_function)
self.help_function = help_function
else:
self.help_function = None
self.function = function
if params:
self.params = params
for arg in chain(self.params.args, self.params.kwargs.values()):
if isinstance(arg, ParamIndex):
self.has_index = True
break
else:
self.has_index = False
else:
self.has_index = False
def execute(self,
option_bag: OptionBag,
leadership_must_have_index: bool=False) -> Any:
if leadership_must_have_index and not self.has_index:
leadership_must_have_index = False
return carry_out_calculation(option_bag.option,
callback=self.function,
callback_params=self.params,
index=option_bag.index,
config_bag=option_bag.config_bag,
fromconsistency=option_bag.fromconsistency,
leadership_must_have_index=leadership_must_have_index)
def help(self,
option_bag: OptionBag,
leadership_must_have_index: bool=False) -> str:
if not self.help_function:
return self.execute(option_bag,
leadership_must_have_index=leadership_must_have_index)
if leadership_must_have_index and not self.has_index:
leadership_must_have_index = False
return carry_out_calculation(option_bag.option,
callback=self.help_function,
callback_params=self.params,
index=option_bag.index,
config_bag=option_bag.config_bag,
fromconsistency=option_bag.fromconsistency,
leadership_must_have_index=leadership_must_have_index)
class Break(Exception):
pass
def manager_callback(callbk: Union[ParamOption, ParamValue], def manager_callback(callbk: Union[ParamOption, ParamValue],
option, option,
index: Optional[int], index: Optional[int],
orig_value, orig_value,
config_bag: ConfigBag, config_bag: ConfigBag,
fromconsistency: List) -> Any: fromconsistency: List,
leadership_must_have_index: bool) -> Any:
"""replace Param by true value""" """replace Param by true value"""
if isinstance(callbk, ParamValue): if isinstance(callbk, ParamValue):
return callbk.value return callbk.value
@ -46,17 +183,24 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
# Not an option, set full context # Not an option, set full context
return config_bag.context.duplicate(force_values=get_default_values_storages(), return config_bag.context.duplicate(force_values=get_default_values_storages(),
force_settings=get_default_settings_storages()) force_settings=get_default_settings_storages())
if isinstance(callbk, ParamSelfOption):
opt = option
else:
# it's ParamOption
opt = callbk.option opt = callbk.option
if opt.issubdyn(): if opt.issubdyn():
opt = opt.to_dynoption(option.rootpath, opt = opt.to_dynoption(option.rootpath,
option.impl_getsuffix()) option.impl_getsuffix())
path = opt.impl_getpath() path = opt.impl_getpath()
is_follower = opt.impl_is_follower()
if leadership_must_have_index and opt.impl_get_leadership() and index is None:
raise Break()
if index is not None and opt.impl_get_leadership() and \ if index is not None and opt.impl_get_leadership() and \
opt.impl_get_leadership().in_same_group(option): opt.impl_get_leadership().in_same_group(option):
if opt == option: if opt == option:
index_ = None index_ = None
with_index = False with_index = False
elif opt.impl_is_follower(): elif is_follower:
index_ = index index_ = index
with_index = False with_index = False
else: else:
@ -66,12 +210,14 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
index_ = None index_ = None
with_index = False with_index = False
if opt == option and orig_value is not undefined and \ if opt == option and orig_value is not undefined and \
(not opt.impl_is_follower() or index is None): (not is_follower or index is None):
return orig_value value = orig_value
else:
# don't validate if option is option that we tried to validate # don't validate if option is option that we tried to validate
config_bag = config_bag.copy() config_bag = config_bag.copy()
config_bag.properties = config_bag.true_properties - {'warnings'}
config_bag.set_permissive() config_bag.set_permissive()
config_bag.properties -= {'warnings'} #config_bag.properties -= {'warnings'}
option_bag = OptionBag() option_bag = OptionBag()
option_bag.set_option(opt, option_bag.set_option(opt,
path, path,
@ -82,19 +228,25 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
if opt == option: if opt == option:
option_bag.config_bag.unrestraint() option_bag.config_bag.unrestraint()
option_bag.config_bag.remove_validation() option_bag.config_bag.remove_validation()
# if we are in properties calculation, cannot calculated properties
option_bag.properties = config_bag.context.cfgimpl_get_settings().getproperties(option_bag,
apply_requires=False)
try: try:
# get value # get value
value = config_bag.context.getattr(path, value = config_bag.context.getattr(path,
option_bag) option_bag)
if with_index: if with_index:
return value[index] value = value[index]
return value
except PropertiesOptionError as err: except PropertiesOptionError as err:
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation # raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
if callbk.notraisepropertyerror: if callbk.notraisepropertyerror or callbk.raisepropertyerror:
raise err raise err
raise ConfigError(_('unable to carry out a calculation for "{}"' raise ConfigError(_('unable to carry out a calculation for "{}"'
', {}').format(option.impl_get_display_name(), err), err) ', {}').format(option.impl_get_display_name(), err), err)
if not callbk.todict:
return value
return {'name': opt.impl_get_display_name(),
'value': value}
def carry_out_calculation(option, def carry_out_calculation(option,
@ -104,8 +256,8 @@ def carry_out_calculation(option,
config_bag: Optional[ConfigBag], config_bag: Optional[ConfigBag],
fromconsistency: List, fromconsistency: List,
orig_value=undefined, orig_value=undefined,
leadership_must_have_index: bool=False,
is_validator: int=False): is_validator: int=False):
"""a function that carries out a calculation for an option's value """a function that carries out a calculation for an option's value
:param option: the option :param option: the option
@ -227,12 +379,18 @@ def carry_out_calculation(option,
index, index,
orig_value, orig_value,
config_bag, config_bag,
fromconsistency) fromconsistency,
leadership_must_have_index)
if value is undefined: if value is undefined:
return undefined return undefined
args.append(value) args.append(value)
except PropertiesOptionError: except PropertiesOptionError as err:
pass if callbk.raisepropertyerror:
raise err
if callbk.todict:
args.append({'propertyerror': str(err)})
except Break:
continue
for key, callbk in callback_params.kwargs.items(): for key, callbk in callback_params.kwargs.items():
try: try:
value = manager_callback(callbk, value = manager_callback(callbk,
@ -240,12 +398,18 @@ def carry_out_calculation(option,
index, index,
orig_value, orig_value,
config_bag, config_bag,
fromconsistency) fromconsistency,
leadership_must_have_index)
if value is undefined: if value is undefined:
return undefined return undefined
kwargs[key] = value kwargs[key] = value
except PropertiesOptionError: except PropertiesOptionError as err:
pass if callbk.raisepropertyerror:
raise err
if callbk.todict:
kwargs[key] = {'propertyerror': str(err)}
except Break:
continue
ret = calculate(option, ret = calculate(option,
callback, callback,
is_validator, is_validator,
@ -290,6 +454,8 @@ def calculate(option,
raise err raise err
error = err error = err
except Exception as err: except Exception as err:
#import traceback
#traceback.print_exc()
error = err error = err
if args or kwargs: if args or kwargs:
msg = _('unexpected error "{0}" in function "{1}" with arguments "{3}" and "{4}" ' msg = _('unexpected error "{0}" in function "{1}" with arguments "{3}" and "{4}" '

View file

@ -269,10 +269,9 @@ class SubConfig(object):
def getattr(self, def getattr(self,
name, name,
option_bag, option_bag,
from_follower=False): from_follower=False,
needs_re_verify_follower_properties=False):
""" """
attribute notation mechanism for accessing the value of an option
:param name: attribute name
:return: option's value if name is an option name, OptionDescription :return: option's value if name is an option name, OptionDescription
otherwise otherwise
""" """
@ -298,7 +297,7 @@ class SubConfig(object):
return context.getattr(soption_bag.path, return context.getattr(soption_bag.path,
soption_bag) soption_bag)
if not from_follower or option_bag.option.impl_getrequires(): if not from_follower or needs_re_verify_follower_properties:
self.cfgimpl_get_settings().validate_properties(option_bag) self.cfgimpl_get_settings().validate_properties(option_bag)
if option.impl_is_follower() and not from_follower: if option.impl_is_follower() and not from_follower:
@ -311,6 +310,8 @@ class SubConfig(object):
length, length,
option_bag.index)) option_bag.index))
if option.impl_is_follower() and option_bag.index is None: if option.impl_is_follower() and option_bag.index is None:
needs_re_verify_follower_properties = option_bag.option.impl_getrequires() or \
self.cfgimpl_get_settings().has_properties_index(option_bag)
value = [] value = []
for idx in range(length): for idx in range(length):
soption_bag = OptionBag() soption_bag = OptionBag()
@ -322,7 +323,8 @@ class SubConfig(object):
try: try:
value.append(self.getattr(name, value.append(self.getattr(name,
soption_bag, soption_bag,
from_follower=True)) from_follower=True,
needs_re_verify_follower_properties=needs_re_verify_follower_properties))
except PropertiesOptionError as err: except PropertiesOptionError as err:
value.append(err) value.append(err)
else: else:
@ -412,40 +414,7 @@ class SubConfig(object):
withoption=None, withoption=None,
withvalue=undefined, withvalue=undefined,
fullpath=False): fullpath=False):
"""exports the whole config into a `dict`, for example: """exports the whole config into a `dict`
>>> print(cfg.make_dict())
{'od2.var4': None, 'od2.var5': None, 'od2.var6': None}
:param flatten: returns a dict(name=value) instead of a dict(path=value)
::
>>> print(cfg.make_dict(flatten=True))
{'var5': None, 'var4': None, 'var6': None}
:param withoption: returns the options that are present in the very same
`OptionDescription` than the `withoption` itself::
>>> print(cfg.make_dict(withoption='var1'))
{'od2.var4': None, 'od2.var5': None,
'od2.var6': None,
'od2.var1': u'value',
'od1.var1': None,
'od1.var3': None,
'od1.var2': None}
:param withvalue: returns the options that have the value `withvalue`
::
>>> print(c.make_dict(withoption='var1',
withvalue=u'value'))
{'od2.var4': None,
'od2.var5': None,
'od2.var6': None,
'od2.var1': u'value'}
:returns: dict of Option's name (or path) and values :returns: dict of Option's name (or path) and values
""" """
pathsvalues = {} pathsvalues = {}

View file

@ -30,7 +30,7 @@ def display_list(lst, separator='and', add_quote=False):
ret = lst[0] ret = lst[0]
if not isinstance(ret, str): if not isinstance(ret, str):
ret = str(ret) ret = str(ret)
if add_quote: if add_quote and not ret.startswith('"'):
ret = '"{}"'.format(ret) ret = '"{}"'.format(ret)
return ret return ret
else: else:
@ -39,13 +39,13 @@ def display_list(lst, separator='and', add_quote=False):
for l in lst[:-1]: for l in lst[:-1]:
if not isinstance(l, str): if not isinstance(l, str):
l = str(l) l = str(l)
if add_quote: if add_quote and not l.startswith('"'):
l = '"{}"'.format(l) l = '"{}"'.format(l)
lst_.append(_(l)) lst_.append(_(l))
last = lst[-1] last = lst[-1]
if not isinstance(last, str): if not isinstance(last, str):
last = str(_(last)) last = str(_(last))
if add_quote: if add_quote and not last.startswith('"'):
last = '"{}"'.format(last) last = '"{}"'.format(last)
return ', '.join(lst_) + _(' {} ').format(separator) + '{}'.format(last) return ', '.join(lst_) + _(' {} ').format(separator) + '{}'.format(last)
@ -91,7 +91,6 @@ class PropertiesOptionError(AttributeError):
return 'error' return 'error'
req = self._settings.apply_requires(self._option_bag, req = self._settings.apply_requires(self._option_bag,
True) True)
#if req != {} or self._orig_opt is not None:
if req != {}: if req != {}:
only_one = len(req) == 1 only_one = len(req) == 1
msg = [] msg = []
@ -99,8 +98,16 @@ class PropertiesOptionError(AttributeError):
msg.append('"{0}" ({1})'.format(action, display_list(msg_, add_quote=False))) msg.append('"{0}" ({1})'.format(action, display_list(msg_, add_quote=False)))
msg = display_list(msg, add_quote=False) msg = display_list(msg, add_quote=False)
else: else:
only_one = len(self.proptype) == 1 properties = list(self._settings.calc_raises_properties(self._option_bag,
msg = display_list(list(self.proptype), add_quote=True) apply_requires=False))
for property_ in self._settings.get_calculated_properties(self._option_bag):
properties.append(property_.help(self._option_bag))
if not properties:
# if proptype == ['mandatory']
properties = self.proptype
only_one = len(properties) == 1
msg = display_list(properties, add_quote=True)
if only_one: if only_one:
prop_msg = _('property') prop_msg = _('property')
else: else:

View file

@ -14,85 +14,25 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from typing import Any, List, Optional from typing import Any, List, Optional
from operator import add, mul, sub, truediv from operator import add, mul, sub, truediv
from .setting import undefined
from .i18n import _ from .i18n import _
from .setting import undefined
from .error import display_list
class Params:
__slots__ = ('args', 'kwargs')
def __init__(self, args=None, kwargs=None, **kwgs):
if args is None:
args = tuple()
if kwargs is None:
kwargs = {}
if kwgs:
kwargs.update(kwgs)
if isinstance(args, Param):
args = (args,)
else:
if not isinstance(args, tuple):
raise ValueError(_('args in params must be a tuple'))
for arg in args:
if not isinstance(arg, Param):
raise ValueError(_('arg in params must be a Param'))
if not isinstance(kwargs, dict):
raise ValueError(_('kwargs in params must be a dict'))
for arg in kwargs.values():
if not isinstance(arg, Param):
raise ValueError(_('arg in params must be a Param'))
self.args = args
self.kwargs = kwargs
class Param:
pass
class ParamOption(Param):
__slots__ = ('option',
'notraisepropertyerror')
def __init__(self,
option: 'Option',
notraisepropertyerror: bool=False) -> 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():
cur_opt = option.impl_getopt()
else:
cur_opt = option
if not isinstance(notraisepropertyerror, bool):
raise ValueError(_('param must have a boolean'
' not a {} for notraisepropertyerror'
).format(type(notraisepropertyerror)))
self.option = cur_opt
self.notraisepropertyerror = notraisepropertyerror
class ParamValue(Param):
__slots__ = ('value',)
def __init__(self, value):
self.value = value
class ParamContext(Param):
__slots__ = tuple()
class ParamIndex(Param):
__slots__ = tuple()
def tiramisu_copy(val): # pragma: no cover def tiramisu_copy(val): # pragma: no cover
return val return val
def calc_value(*args: List[Any], class CalcValue:
def __call__(self,
*args: List[Any],
multi: bool=False, multi: bool=False,
default: Any=undefined, default: Any=undefined,
condition: Any=undefined, condition: Any=undefined,
no_condition_is_invalid: Any=False,
expected: Any=undefined, expected: Any=undefined,
condition_operator: str='AND', condition_operator: str='AND',
inverse_condition: bool=False,
allow_none: bool=False, allow_none: bool=False,
remove_duplicate_value: bool=False, remove_duplicate_value: bool=False,
join: Optional[str]=None, join: Optional[str]=None,
@ -101,6 +41,7 @@ def calc_value(*args: List[Any],
index: Optional[int]=None, index: Optional[int]=None,
**kwargs) -> Any: **kwargs) -> Any:
"""calculate value """calculate value
:param args: list of value
:param multi: value returns must be a list of value :param multi: value returns must be a list of value
:param default: default value if condition is not matched or if args is empty :param default: default value if condition is not matched or if args is empty
if there is more than one default value, set default_0, default_1, ... if there is more than one default value, set default_0, default_1, ...
@ -108,12 +49,15 @@ def calc_value(*args: List[Any],
if there is more than one condition, set condition_0, condition_1, ... if there is more than one condition, set condition_0, condition_1, ...
:param expected: value expected for all conditions :param expected: value expected for all conditions
if expected value is different between condition, set expected_0, expected_1, ... if expected value is different between condition, set expected_0, expected_1, ...
:param no_condition_is_invalid: if no condition and not condition_0, condition_1, ... (for
example if option is disabled) consider that condition not matching
:param condition_operator: OR or AND operator for condition :param condition_operator: OR or AND operator for condition
:param allow_none: if False, do not return list in None is present in list :param allow_none: if False, do not return list in None is present in list
:param remove_duplicate_value: if True, remote duplicated value :param remove_duplicate_value: if True, remote duplicated value
:param join: join all args with specified characters :param join: join all args with specified characters
:param min_args_len: if number of arguments is smaller than this value, return default value :param min_args_len: if number of arguments is smaller than this value, return default value
:param operator: operator :param operator: 'add', 'mul', 'div' or 'sub' all args (args must be integer value)
:param index: index for follower
examples: examples:
* you want to copy value from an option to an other option: * you want to copy value from an option to an other option:
@ -135,7 +79,7 @@ def calc_value(*args: List[Any],
>>> cfg.value.dict() >>> cfg.value.dict()
{'val1': 'val1', 'val2': 'val2', 'val3': ['val1', 'val2']} {'val1': 'val1', 'val2': 'val2', 'val3': ['val1', 'val2']}
* you want to copy a value from an option is it not disabled, otherwise set 'default_value' * you want to copy a value from an option if it not disabled, otherwise set 'default_value'
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue >>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue
>>> val1 = StrOption('val1', '', 'val1') >>> val1 = StrOption('val1', '', 'val1')
>>> val2 = StrOption('val2', '', callback=calc_value, callback_params=Params(ParamOption(val1, True), default=ParamValue('default_value'))) >>> val2 = StrOption('val2', '', callback=calc_value, callback_params=Params(ParamOption(val1, True), default=ParamValue('default_value')))
@ -148,7 +92,7 @@ def calc_value(*args: List[Any],
>>> cfg.value.dict() >>> cfg.value.dict()
{'val2': 'default_value'} {'val2': 'default_value'}
* you want to copy value from an option is an other is True, otherwise set 'default_value' * you want to copy value from an option if an other is True, otherwise set 'default_value'
>>> from tiramisu import calc_value, BoolOption, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue >>> from tiramisu import calc_value, BoolOption, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue
>>> boolean = BoolOption('boolean', '', True) >>> boolean = BoolOption('boolean', '', True)
>>> val1 = StrOption('val1', '', 'val1') >>> val1 = StrOption('val1', '', 'val1')
@ -221,77 +165,15 @@ def calc_value(*args: List[Any],
{'val1': 1, 'val2': 2, 'val3': 3} {'val1': 1, 'val2': 2, 'val3': 3}
""" """
def value_from_kwargs(value: Any, pattern: str, to_dict: bool=False) -> Any: self.args = args
# if value attribute exist return it's value self.condition = condition
# otherwise pattern_0, pattern_1, ... self.expected = expected
# otherwise undefined self.condition_operator = condition_operator
if value is not undefined: self.inverse_condition = inverse_condition
if to_dict == 'all': self.kwargs = kwargs
returns = {0: value} self.no_condition_is_invalid = no_condition_is_invalid
else: value = self.get_value(default,
returns = value min_args_len)
else:
kwargs_matches = {}
len_pattern = len(pattern)
for key in kwargs.keys():
if key.startswith(pattern):
index = int(key[len_pattern:])
kwargs_matches[index] = kwargs[key]
if not kwargs_matches:
return undefined
keys = sorted(kwargs_matches)
if to_dict:
returns = {}
else:
returns = []
for key in keys:
if to_dict:
returns[key] = kwargs_matches[key]
else:
returns.append(kwargs_matches[key])
return returns
def is_condition_matches():
calculated_conditions = value_from_kwargs(condition, 'condition_', to_dict='all')
if condition is not undefined:
is_matches = None
calculated_expected = value_from_kwargs(expected, 'expected_', to_dict=True)
for idx, calculated_condition in calculated_conditions.items():
if isinstance(calculated_expected, dict):
current_matches = calculated_condition == calculated_expected[idx]
else:
current_matches = calculated_condition == calculated_expected
if is_matches is None:
is_matches = current_matches
elif condition_operator == 'AND':
is_matches = is_matches and current_matches
elif condition_operator == 'OR':
is_matches = is_matches or current_matches
else:
raise ValueError(_('unexpected {} condition_operator in calc_value').format(condition_operator))
else:
is_matches = True
return is_matches
def get_value():
if not is_condition_matches():
# force to default
value = []
else:
value = list(args)
if min_args_len and not len(value) >= min_args_len:
value = []
if value == []:
# default value
new_default = value_from_kwargs(default, 'default_')
if new_default is not undefined:
if not isinstance(new_default, list):
value = [new_default]
else:
value = new_default
return value
value = get_value()
if not multi: if not multi:
if join is not None: if join is not None:
value = join.join(value) value = join.join(value)
@ -322,3 +204,188 @@ def calc_value(*args: List[Any],
new_value.append(val) new_value.append(val)
value = new_value value = new_value
return value return value
def value_from_kwargs(self,
value: Any,
pattern: str,
to_dict: bool=False,
empty_test=undefined) -> Any:
# if value attribute exist return it's value
# otherwise pattern_0, pattern_1, ...
# otherwise undefined
if value is not empty_test:
if to_dict == 'all':
returns = {None: value}
else:
returns = value
else:
kwargs_matches = {}
len_pattern = len(pattern)
for key in self.kwargs.keys():
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
if not kwargs_matches:
returns = undefined
else:
keys = sorted(kwargs_matches)
if to_dict:
returns = {}
else:
returns = []
for key in keys:
if to_dict:
returns[key] = kwargs_matches[key]
else:
returns.append(kwargs_matches[key])
return returns
def is_condition_matches(self,
condition_value):
calculated_conditions = self.value_from_kwargs(condition_value,
'condition_',
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)
calculated_inverse = self.value_from_kwargs(self.inverse_condition,
'inverse_condition_',
to_dict=True,
empty_test=False)
for idx, calculated_condition in calculated_conditions.items():
if isinstance(calculated_expected, dict):
if idx is not None:
current_matches = calculated_condition == calculated_expected[idx]
else:
current_matches = calculated_condition in calculated_expected.values()
else:
current_matches = calculated_condition == calculated_expected
if isinstance(calculated_inverse, dict) and idx in calculated_inverse:
inverse_condition = calculated_inverse[idx]
else:
inverse_condition = False
if is_matches is None:
is_matches = current_matches
if self.condition_operator == 'AND':
is_matches = is_matches and current_matches
if inverse_condition:
is_matches = not is_matches
if not is_matches:
break
elif self.condition_operator == 'OR':
is_matches = is_matches or current_matches
if inverse_condition:
is_matches = not is_matches
if is_matches:
break
else:
raise ValueError(_('unexpected {} condition_operator in calc_value').format(self.condition_operator))
is_matches = is_matches and not self.inverse_condition \
or not is_matches and self.inverse_condition
return is_matches
def get_value(self,
default,
min_args_len):
if isinstance(self.condition, dict):
if 'value' in self.condition:
condition_value = self.condition['value']
else:
condition_value = undefined
else:
condition_value = self.condition
condition_matches = self.is_condition_matches(condition_value)
if not condition_matches:
# force to default
value = []
else:
value = self.get_args()
if min_args_len and not len(value) >= min_args_len:
value = []
if value == []:
# default value
new_default = self.value_from_kwargs(default,
'default_')
if new_default is not undefined:
if not isinstance(new_default, list):
value = [new_default]
else:
value = new_default
return value
def get_args(self):
return list(self.args)
class CalcValuePropertyHelp(CalcValue):
def get_name(self):
return self.condition['name']
def get_indexed_name(self, index):
return self.kwargs.get(f'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 inverse:
# msg = _('the calculated value is {0}').format(display_value)
# else:
# msg = _('the calculated value is not {0}').format(display_value)
#else:
if not self.inverse_condition:
msg = _('the value of "{0}" is {1}').format(name, value)
else:
msg = _('the value of "{0}" is not {1}').format(name, value)
return msg
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())
else:
return [f'"{action}"']
return [f'"{action}" ({msg})']
return
## calc_properties.setdefault(action, []).append(msg)
calc_value = CalcValue()
calc_value.__name__ = 'calc_value'
calc_value_property_help = CalcValuePropertyHelp()
calc_value_property_help.__name__ = 'calc_value_property_help'

View file

@ -29,7 +29,7 @@ from ..i18n import _
from ..setting import undefined, Settings from ..setting import undefined, Settings
from ..value import Values from ..value import Values
from ..error import ConfigError, display_list from ..error import ConfigError, display_list
from ..function import Params, ParamContext, ParamOption, ParamIndex from ..autolib import Calculation, Params, ParamContext, ParamOption, ParamIndex
STATIC_TUPLE = frozenset() STATIC_TUPLE = frozenset()
@ -83,16 +83,15 @@ class Base:
requires = undefined requires = undefined
if properties is None: if properties is None:
properties = frozenset() properties = frozenset()
if isinstance(properties, tuple): elif isinstance(properties, tuple):
properties = frozenset(properties) properties = frozenset(properties)
if is_multi and 'empty' not in properties: if is_multi and 'empty' not in properties:
# if option is a multi, it cannot be "empty" (None not allowed in the list) # if option is a multi, it cannot be "empty" (None not allowed in the list)
# "empty" is removed for follower's option # "empty" is removed for follower's option
properties = properties | {'empty'} properties = properties | {'empty'}
if not isinstance(properties, frozenset): assert isinstance(properties, frozenset), _('invalid properties type {0} for {1},'
raise TypeError(_('invalid properties type {0} for {1},'
' must be a frozenset').format(type(properties), ' must be a frozenset').format(type(properties),
name)) name)
self.validate_properties(name, self.validate_properties(name,
calc_properties, calc_properties,
properties) properties)
@ -115,6 +114,17 @@ class Base:
raise ValueError(_('conflict: properties already set in requirement {0} for {1}' raise ValueError(_('conflict: properties already set in requirement {0} for {1}'
'').format(display_list(set_forbidden_properties, add_quote=True), '').format(display_list(set_forbidden_properties, add_quote=True),
name)) name))
assert isinstance(properties, frozenset), _('invalid properties type {0} for {1},'
' must be a frozenset').format(type(properties),
name)
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))
params = prop.params
for param in chain(params.args, params.kwargs.values()):
if isinstance(param, ParamOption):
param.option._add_dependency(self)
def _get_function_args(self, def _get_function_args(self,
function: Callable) -> Tuple[Set[str], Set[str], bool, bool]: function: Callable) -> Tuple[Set[str], Set[str], bool, bool]:
@ -159,7 +169,7 @@ class Base:
""" """
:add_value: add value as first argument for validator :add_value: add value as first argument for validator
""" """
assert isinstance(calculator, FunctionType), _('{0} must be a function').format(type_) assert isinstance(calculator, Callable), _('{0} must be a function').format(type_)
if calculator_params is not None: if calculator_params is not None:
assert isinstance(calculator_params, Params), _('{0}_params must be a params' assert isinstance(calculator_params, Params), _('{0}_params must be a params'
'').format(type_) '').format(type_)

View file

@ -32,7 +32,7 @@ from .syndynoptiondescription import SynDynLeadership
from .baseoption import BaseOption from .baseoption import BaseOption
from .option import Option from .option import Option
from ..error import RequirementError from ..error import RequirementError
from ..function import ParamOption from ..autolib import ParamOption
class Leadership(OptionDescription): class Leadership(OptionDescription):
@ -97,11 +97,8 @@ class Leadership(OptionDescription):
raise RequirementError(_('leader {} have requirement, but Leadership {} too' raise RequirementError(_('leader {} have requirement, but Leadership {} too'
'').format(leader.impl_getname(), '').format(leader.impl_getname(),
self.impl_getname())) self.impl_getname()))
leader_calproperties = getattr(leader, '_calc_properties', None) leader_calproperties = getattr(leader, '_requires', None)
if leader_calproperties: if leader_calproperties:
if __debug__ and properties is not None:
self.validate_properties(name, leader_calproperties, frozenset(properties))
setattr(self, '_calc_properties', leader_calproperties)
setattr(self, '_requires', leader_requires) setattr(self, '_requires', leader_requires)
delattr(leader, '_requires') delattr(leader, '_requires')
if __debug__: if __debug__:

View file

@ -26,10 +26,9 @@ from typing import Any, List, Callable, Optional, Dict, Union, Tuple
from .baseoption import BaseOption, submulti, STATIC_TUPLE from .baseoption import BaseOption, submulti, STATIC_TUPLE
from ..i18n import _ from ..i18n import _
from ..setting import undefined, OptionBag, Undefined from ..setting import undefined, OptionBag, Undefined
from ..autolib import carry_out_calculation from ..autolib import carry_out_calculation, Params, ParamValue
from ..error import (ConfigError, ValueWarning, ValueErrorWarning, PropertiesOptionError, from ..error import (ConfigError, ValueWarning, ValueErrorWarning, PropertiesOptionError,
ValueOptionError, display_list) ValueOptionError, display_list)
from ..function import Params, ParamValue
from .syndynoption import SynDynOption from .syndynoption import SynDynOption
ALLOWED_CONST_LIST = ['_cons_not_equal'] ALLOWED_CONST_LIST = ['_cons_not_equal']

View file

@ -38,6 +38,9 @@ class SynDynOptionDescription:
subpath: str, subpath: str,
suffix: str) -> None: suffix: str) -> None:
self._opt = opt self._opt = opt
if subpath is None:
subpath = ''
assert isinstance(subpath, str), 'subpath must be a string, not {}'.format(type(subpath))
self._subpath = subpath self._subpath = subpath
self._suffix = suffix self._suffix = suffix

View file

@ -415,13 +415,13 @@ class Settings(object):
search_properties=None): search_properties=None):
""" """
""" """
opt = option_bag.option # FIXME search_properties
option = option_bag.option
config_bag = option_bag.config_bag config_bag = option_bag.config_bag
path = option_bag.path if option.impl_is_symlinkoption():
option = option.impl_getopt()
path = option.impl_getpath()
index = option_bag.index index = option_bag.index
if opt.impl_is_symlinkoption():
opt = opt.impl_getopt()
path = opt.impl_getpath()
if apply_requires: if apply_requires:
cache = config_bag.context._impl_properties_cache cache = config_bag.context._impl_properties_cache
@ -435,13 +435,28 @@ class Settings(object):
else: else:
is_cached = False is_cached = False
if not is_cached: if not is_cached:
props = self._p_.getproperties(path, props = set()
opt.impl_getproperties()) for prop in self._p_.getproperties(path,
option.impl_getproperties()):
if isinstance(prop, str):
props.add(prop)
elif apply_requires:
new_props = prop.execute(option_bag,
leadership_must_have_index=True)
if not new_props:
continue
elif not isinstance(new_props, str):
raise ValueError(_('invalid property type {} for {} with {} function').format(type(new_props),
option_bag.option.impl_getname(),
prop.function.__name__))
props.add(new_props)
# else:
# props.update(new_props)
if apply_requires: if apply_requires:
props |= self.apply_requires(option_bag, props |= self.apply_requires(option_bag,
False, False,
search_properties=search_properties) search_properties=search_properties)
props -= self.getpermissives(opt, props -= self.getpermissives(option,
path) path)
#if apply_requires and config_bag.properties == config_bag.true_properties: #if apply_requires and config_bag.properties == config_bag.true_properties:
if apply_requires and not config_bag.is_unrestraint: if apply_requires and not config_bag.is_unrestraint:
@ -453,6 +468,29 @@ class Settings(object):
True) True)
return props return props
def get_calculated_properties(self,
option_bag):
opt = option_bag.option
if opt.impl_is_symlinkoption():
opt = opt.impl_getopt()
path = opt.impl_getpath()
for prop in self._p_.getproperties(path,
opt.impl_getproperties()):
if not isinstance(prop, str):
yield prop
def has_properties_index(self,
option_bag):
opt = option_bag.option
if opt.impl_is_symlinkoption():
opt = opt.impl_getopt()
path = opt.impl_getpath()
for prop in self._p_.getproperties(path,
opt.impl_getproperties()):
if not isinstance(prop, str) and prop.has_index:
return True
return False
def get_context_permissives(self): def get_context_permissives(self):
return self.getpermissives(None, None) return self.getpermissives(None, None)
@ -670,7 +708,6 @@ class Settings(object):
"""save properties for specified path """save properties for specified path
(never save properties if same has option properties) (never save properties if same has option properties)
""" """
# should have index !!!
opt = option_bag.option opt = option_bag.option
if opt.impl_getrequires() is not None: if opt.impl_getrequires() is not None:
not_allowed_props = properties & \ not_allowed_props = properties & \

View file

@ -31,7 +31,7 @@ from os.path import split
from typing import Dict from typing import Dict
from ..error import ConfigError from ..error import ConfigError
from ..i18n import _ from ..i18n import _
from .util import Cache from .cacheobj import Cache
DEFAULT_STORAGE = MEMORY_STORAGE = 'dictionary' DEFAULT_STORAGE = MEMORY_STORAGE = 'dictionary'

View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"utils used by storage" "cache used by storage"
# Copyright (C) 2013-2019 Team tiramisu (see AUTHORS for all contributors) # Copyright (C) 2013-2019 Team tiramisu (see AUTHORS for all contributors)
# #
# This program is free software: you can redistribute it and/or modify it # This program is free software: you can redistribute it and/or modify it

View file

@ -15,10 +15,11 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# ____________________________________________________________ # ____________________________________________________________
import sqlite3
import warnings
from ...i18n import _ from ...i18n import _
from os.path import join from os.path import join
import sqlite3
from ...error import ConflictError from ...error import ConflictError
@ -55,6 +56,13 @@ def _gen_filename():
def list_sessions(): def list_sessions():
if not CONN:
warnings.warn_explicit(Warning(_('Cannot list sessions, please connect to database first')),
category=Warning,
filename=__file__,
lineno=63)
return []
else:
cursor = CONN.cursor() cursor = CONN.cursor()
names = [row[0] for row in cursor.execute("SELECT session FROM session").fetchall()] names = [row[0] for row in cursor.execute("SELECT session FROM session").fetchall()]
return names return names

View file

@ -19,8 +19,7 @@ import weakref
from typing import Optional, Any, Callable from typing import Optional, Any, Callable
from .error import ConfigError, PropertiesOptionError, RequirementError from .error import ConfigError, PropertiesOptionError, RequirementError
from .setting import owners, undefined, forbidden_owners, OptionBag, ConfigBag from .setting import owners, undefined, forbidden_owners, OptionBag, ConfigBag
from .autolib import carry_out_calculation from .autolib import carry_out_calculation, Params
from .function import Params
from .i18n import _ from .i18n import _