feat: dynoption

This commit is contained in:
egarette@silique.fr 2024-02-08 08:32:24 +01:00
parent 93fa26f8df
commit a6eacf471e
19 changed files with 913 additions and 408 deletions

View file

@ -11,13 +11,12 @@ You just have to create an object that inherits from `RegexpOption` and that has
- __slots__: with new data members (the values should always be `tuple()`) - __slots__: with new data members (the values should always be `tuple()`)
- _type = with a name - _type = with a name
- _display_name: with the display name (for example in error message)
- _regexp: with a compiled regexp - _regexp: with a compiled regexp
Here an example to an option that only accept string with on lowercase ASCII vowel characters: Here an example to an option that only accept string with on lowercase ASCII vowel characters:
.. literalinclude:: src/own_option.py .. literalinclude:: src/own_option.py
:lines: 3-11 :lines: 3-10
:linenos: :linenos:
Let's try our object: Let's try our object:
@ -31,31 +30,30 @@ Let's try our object:
... ...
"oooups" is an invalid string with vowel for "Vowel" "oooups" is an invalid string with vowel for "Vowel"
Create you own option Create your own option
================================= =================================
An option always inherits from `Option` object. This object has the following class attributes: An option always inherits from `Option` object. This object has the following class attributes:
- __slots__: with new data members (the values should always be `tuple()`) - __slots__: with new data members (the values should always be `tuple()`)
- _type = with a name - _type = with a name
- _display_name: with the display name (for example in error message)
Here an example to an lipogram option: Here an example to a lipogram option:
.. literalinclude:: src/own_option2.py .. literalinclude:: src/own_option2.py
:lines: 3-15 :lines: 3-12
:linenos: :linenos:
First of all we want to add a custom parameter to ask the minimum length (`min_len`) of the value: First of all we want to add a custom parameter to ask the minimum length (`min_len`) of the value:
.. literalinclude:: src/own_option2.py .. literalinclude:: src/own_option2.py
:lines: 16-20 :lines: 13-17
:linenos: :linenos:
We have a first validation method. In this method, we verify that the value is a string and that there is no "e" on it: We have a first validation method. In this method, we verify that the value is a string and that there is no "e" on it:
.. literalinclude:: src/own_option2.py .. literalinclude:: src/own_option2.py
:lines: 22-29 :lines: 19-26
:linenos: :linenos:
Even if user set warnings_only attribute, this method will raise. Even if user set warnings_only attribute, this method will raise.
@ -63,7 +61,7 @@ Even if user set warnings_only attribute, this method will raise.
Finally we add a method to valid the value length. If `warnings_only` is set to True, a warning will be emit: Finally we add a method to valid the value length. If `warnings_only` is set to True, a warning will be emit:
.. literalinclude:: src/own_option2.py .. literalinclude:: src/own_option2.py
:lines: 31-43 :lines: 28-40
:linenos: :linenos:
Let's test it: Let's test it:

View file

@ -7,5 +7,4 @@ from tiramisu import RegexpOption
class VowelOption(RegexpOption): class VowelOption(RegexpOption):
__slots__ = tuple() __slots__ = tuple()
_type = 'vowel' _type = 'vowel'
_display_name = "string with vowel"
_regexp = re.compile(r"^[aeiouy]*$") _regexp = re.compile(r"^[aeiouy]*$")

View file

@ -1,14 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from tiramisu import Option from tiramisu import Option
from tiramisu.error import ValueWarning
import warnings
class LipogramOption(Option): class LipogramOption(Option):
__slots__ = tuple() __slots__ = tuple()
_type = 'lipogram' _type = 'lipogram'
_display_name = 'lipogram'
def __init__(self, def __init__(self,
*args, *args,
min_len=100, min_len=100,

View file

@ -66,7 +66,7 @@ def test_deref_optiondescription():
def test_deref_option_cache(): def test_deref_option_cache():
b = BoolOption('b', '') b = BoolOption('b', '')
o = OptionDescription('od', '', [b]) o = OptionDescription('od', '', [b])
o._build_cache() o._build_cache(None)
w = weakref.ref(b) w = weakref.ref(b)
del(b) del(b)
assert w() is not None assert w() is not None
@ -77,7 +77,7 @@ def test_deref_option_cache():
def test_deref_optiondescription_cache(): def test_deref_optiondescription_cache():
b = BoolOption('b', '') b = BoolOption('b', '')
o = OptionDescription('od', '', [b]) o = OptionDescription('od', '', [b])
o._build_cache() o._build_cache(None)
w = weakref.ref(o) w = weakref.ref(o)
del(b) del(b)
assert w() is not None assert w() is not None

View file

@ -158,10 +158,10 @@ def test_getdoc_dyndescription():
assert cfg.option('od.dodval2.st').name() == 'st' assert cfg.option('od.dodval2.st').name() == 'st'
assert cfg.option('od.dodval1').name() == 'dodval1' assert cfg.option('od.dodval1').name() == 'dodval1'
assert cfg.option('od.dodval2').name() == 'dodval2' assert cfg.option('od.dodval2').name() == 'dodval2'
assert cfg.option('od.dodval1.st').doc() == 'doc1val1' assert cfg.option('od.dodval1.st').doc() == 'doc1'
assert cfg.option('od.dodval2.st').doc() == 'doc1val2' assert cfg.option('od.dodval2.st').doc() == 'doc1'
assert cfg.option('od.dodval1').doc() == 'doc2val1' assert cfg.option('od.dodval1').doc() == 'doc2'
assert cfg.option('od.dodval2').doc() == 'doc2val2' assert cfg.option('od.dodval2').doc() == 'doc2'
# assert not list_sessions() # assert not list_sessions()
@ -1792,7 +1792,6 @@ def test_subdynod_dyndescription():
assert cfg.option('st3').value.get() is None assert cfg.option('st3').value.get() is None
# assert not list_sessions() # assert not list_sessions()
#FIXME une option dans une dyn qui est utilisé pour calculé dans une subdyn DOIT être dans le meme répertoire pour le moment !
def test_subdynod_dyndescription_2(): def test_subdynod_dyndescription_2():
st2 = StrOption('st2', '') st2 = StrOption('st2', '')
st1 = StrOption('st1', '', default=['a', 'b'], multi=True) st1 = StrOption('st1', '', default=['a', 'b'], multi=True)
@ -2079,7 +2078,7 @@ def test_dyn_leadership_mandatory():
dyn = DynOptionDescription(name="nsd_zone_", doc="Zone ", suffixes=Calculation(calc_value, Params((ParamOption(nsd_zones_all, notraisepropertyerror=True)))), children=[is_auto, leadership], properties=frozenset({"normal"})) dyn = DynOptionDescription(name="nsd_zone_", doc="Zone ", suffixes=Calculation(calc_value, Params((ParamOption(nsd_zones_all, notraisepropertyerror=True)))), children=[is_auto, leadership], properties=frozenset({"normal"}))
od1 = OptionDescription(name="nsd", doc="nsd", children=[nsd_zones_all, dyn]) od1 = OptionDescription(name="nsd", doc="nsd", children=[nsd_zones_all, dyn])
cfg = Config(od1) cfg = Config(od1)
cfg.value.mandatory() assert cfg.value.mandatory() == []
# assert not list_sessions() # assert not list_sessions()
@ -2109,3 +2108,542 @@ def test_dyn_callback_with_not_dyn():
assert cfg.option('names').issubmulti() == False assert cfg.option('names').issubmulti() == False
assert cfg.value.get() == {'remotes': ['a', 'b', 'c'], 'remote_a.remote_ip_': 'a', 'remote_b.remote_ip_': 'b', 'remote_c.remote_ip_': 'c', 'names': ['a', 'b', 'c']} assert cfg.value.get() == {'remotes': ['a', 'b', 'c'], 'remote_a.remote_ip_': 'a', 'remote_b.remote_ip_': 'b', 'remote_c.remote_ip_': 'c', 'names': ['a', 'b', 'c']}
# assert not list_sessions() # assert not list_sessions()
def test_dyn_link_subdyn():
database_names = StrOption(name="database_names", doc="database_names", multi=True, default=["srep", "snom", "srem"])
password = StrOption(name="password", doc="password", properties=('mandatory',))
name = StrOption(name="name", doc="name", properties=('mandatory',))
password2 = StrOption(name="password", doc="password", default=Calculation(calc_value, Params((ParamOption(password)))), properties=('mandatory',))
user = OptionDescription(name="user", doc="user", children=[name, password2])
sub = OptionDescription(name="sub", doc="sub", children=[user])
user_database = DynOptionDescription(name="user_database_", doc="user database", suffixes=Calculation(calc_value, Params((ParamOption(database_names, notraisepropertyerror=True)))), children=[password, sub])
socle = OptionDescription(name="socle", doc="socle", children=[user_database, database_names])
root = OptionDescription(name="baseoption", doc="baseoption", children=[socle])
cfg = Config(root)
assert cfg.option('socle.database_names').value.get() == ["srep", "snom", "srem"]
assert cfg.option('socle.user_database_srep.password').value.get() is None
assert cfg.option('socle.user_database_srep.sub.user.name').value.get() is None
assert cfg.option('socle.user_database_srep.sub.user.password').value.get() is None
assert [opt.path() for opt in cfg.value.mandatory()] == ['socle.user_database_srep.password',
'socle.user_database_srep.sub.user.name',
'socle.user_database_srep.sub.user.password',
'socle.user_database_snom.password',
'socle.user_database_snom.sub.user.name',
'socle.user_database_snom.sub.user.password',
'socle.user_database_srem.password',
'socle.user_database_srem.sub.user.name',
'socle.user_database_srem.sub.user.password',
]
#
cfg.option('socle.user_database_srep.password').value.set('pass')
cfg.option('socle.user_database_snom.sub.user.password').value.set('pass')
assert cfg.option('socle.user_database_srep.password').value.get() is 'pass'
assert cfg.option('socle.user_database_srep.sub.user.name').value.get() is None
assert cfg.option('socle.user_database_srep.sub.user.password').value.get() is 'pass'
assert [opt.path() for opt in cfg.value.mandatory()] == ['socle.user_database_srep.sub.user.name',
'socle.user_database_snom.password',
'socle.user_database_snom.sub.user.name',
'socle.user_database_srem.password',
'socle.user_database_srem.sub.user.name',
'socle.user_database_srem.sub.user.password',
]
#
cfg.option('socle.user_database_snom.password').value.set('pass2')
cfg.option('socle.user_database_srem.password').value.set('pass3')
cfg.option('socle.user_database_srep.sub.user.name').value.set('name1')
cfg.option('socle.user_database_snom.sub.user.name').value.set('name2')
cfg.option('socle.user_database_srem.sub.user.name').value.set('name3')
assert [opt.path() for opt in cfg.value.mandatory()] == []
assert cfg.value.get() == {'socle.database_names': ['srep',
'snom',
'srem'],
'socle.user_database_snom.password': 'pass2',
'socle.user_database_snom.sub.user.name': 'name2',
'socle.user_database_snom.sub.user.password': 'pass',
'socle.user_database_srem.password': 'pass3',
'socle.user_database_srem.sub.user.name': 'name3',
'socle.user_database_srem.sub.user.password': 'pass3',
'socle.user_database_srep.password': 'pass',
'socle.user_database_srep.sub.user.name': 'name1',
'socle.user_database_srep.sub.user.password': 'pass',
}
#
assert [opt.path() for opt in cfg.value.mandatory()] == []
def test_dyn_link_subdyn_2():
database_names = StrOption(name="database_names", doc="database_names", multi=True, default=["srep", "snom", "srem"])
password2 = StrOption(name="password", doc="password", properties=('mandatory',))
password = StrOption(name="password", doc="password", default=Calculation(calc_value, Params((ParamOption(password2)))), properties=('mandatory',))
name = StrOption(name="name", doc="name", properties=('mandatory',))
user = OptionDescription(name="user", doc="user", children=[name, password2])
sub = OptionDescription(name="sub", doc="sub", children=[user])
user_database = DynOptionDescription(name="user_database_", doc="user database", suffixes=Calculation(calc_value, Params((ParamOption(database_names, notraisepropertyerror=True)))), children=[password, sub])
socle = OptionDescription(name="socle", doc="socle", children=[user_database, database_names])
root = OptionDescription(name="baseoption", doc="baseoption", children=[socle])
cfg = Config(root)
assert cfg.option('socle.database_names').value.get() == ["srep", "snom", "srem"]
assert cfg.option('socle.user_database_srep.password').value.get() is None
assert cfg.option('socle.user_database_srep.sub.user.name').value.get() is None
assert cfg.option('socle.user_database_srep.sub.user.password').value.get() is None
assert [opt.path() for opt in cfg.value.mandatory()] == ['socle.user_database_srep.password',
'socle.user_database_srep.sub.user.name',
'socle.user_database_srep.sub.user.password',
'socle.user_database_snom.password',
'socle.user_database_snom.sub.user.name',
'socle.user_database_snom.sub.user.password',
'socle.user_database_srem.password',
'socle.user_database_srem.sub.user.name',
'socle.user_database_srem.sub.user.password',
]
#
cfg.option('socle.user_database_srep.password').value.set('pass')
cfg.option('socle.user_database_snom.sub.user.password').value.set('pass')
assert cfg.option('socle.user_database_srep.password').value.get() is 'pass'
assert cfg.option('socle.user_database_srep.sub.user.name').value.get() is None
assert cfg.option('socle.user_database_srep.sub.user.password').value.get() is None
assert [opt.path() for opt in cfg.value.mandatory()] == ['socle.user_database_srep.sub.user.name',
'socle.user_database_srep.sub.user.password',
'socle.user_database_snom.sub.user.name',
'socle.user_database_srem.password',
'socle.user_database_srem.sub.user.name',
'socle.user_database_srem.sub.user.password',
]
#
cfg.option('socle.user_database_srep.sub.user.password').value.set('pass2')
cfg.option('socle.user_database_srem.sub.user.password').value.set('pass3')
cfg.option('socle.user_database_srep.sub.user.name').value.set('name1')
cfg.option('socle.user_database_snom.sub.user.name').value.set('name2')
cfg.option('socle.user_database_srem.sub.user.name').value.set('name3')
assert [opt.path() for opt in cfg.value.mandatory()] == []
assert cfg.value.get() == {'socle.database_names': ['srep',
'snom',
'srem'],
'socle.user_database_snom.password': 'pass',
'socle.user_database_snom.sub.user.name': 'name2',
'socle.user_database_snom.sub.user.password': 'pass',
'socle.user_database_srem.password': 'pass3',
'socle.user_database_srem.sub.user.name': 'name3',
'socle.user_database_srem.sub.user.password': 'pass3',
'socle.user_database_srep.password': 'pass',
'socle.user_database_srep.sub.user.name': 'name1',
'socle.user_database_srep.sub.user.password': 'pass2',
}
#
assert [opt.path() for opt in cfg.value.mandatory()] == []
def test_dyn_link_subdyn_twice():
password = StrOption(name="password", doc="password", properties=('mandatory',))
name = StrOption(name="name", doc="name", properties=('mandatory',))
login = StrOption(name="login", doc="login", default=Calculation(calc_value, Params((ParamOption(name)))), properties=('mandatory',))
password2 = StrOption(name="password2", doc="password2", default=Calculation(calc_value, Params((ParamOption(password)))), properties=('mandatory',))
database_names = StrOption(name="database_names", doc="database_names", multi=True, default=["srep", "snom", "srem"])
user_database = DynOptionDescription(name="user_database_", doc="user database", suffixes=Calculation(calc_value, Params((ParamOption(database_names, notraisepropertyerror=True)))), children=[name, login, password2])
databases = OptionDescription(name="databases", doc="database", children=[password, user_database])
schema_names = StrOption(name="database_schemas", doc="database_schemas", multi=True, default=["schema1", "schema2", "schema3"])
schema = DynOptionDescription(name="schema_", doc="schema_", suffixes=Calculation(calc_value, Params((ParamOption(schema_names, notraisepropertyerror=True)))), children=[database_names, databases])
socle = OptionDescription(name="socle", doc="socle", children=[schema, schema_names])
root = OptionDescription(name="baseoption", doc="baseoption", children=[socle])
cfg = Config(root)
assert cfg.value.get() == {'socle.database_schemas': ['schema1',
'schema2',
'schema3'],
'socle.schema_schema1.database_names': ['srep',
'snom',
'srem'],
'socle.schema_schema1.databases.password': None,
'socle.schema_schema1.databases.user_database_snom.name': None,
'socle.schema_schema1.databases.user_database_snom.login': None,
'socle.schema_schema1.databases.user_database_snom.password2': None,
'socle.schema_schema1.databases.user_database_srem.name': None,
'socle.schema_schema1.databases.user_database_srem.login': None,
'socle.schema_schema1.databases.user_database_srem.password2': None,
'socle.schema_schema1.databases.user_database_srep.name': None,
'socle.schema_schema1.databases.user_database_srep.login': None,
'socle.schema_schema1.databases.user_database_srep.password2': None,
'socle.schema_schema2.database_names': ['srep',
'snom',
'srem'],
'socle.schema_schema2.databases.password': None,
'socle.schema_schema2.databases.user_database_snom.name': None,
'socle.schema_schema2.databases.user_database_snom.login': None,
'socle.schema_schema2.databases.user_database_snom.password2': None,
'socle.schema_schema2.databases.user_database_srem.name': None,
'socle.schema_schema2.databases.user_database_srem.login': None,
'socle.schema_schema2.databases.user_database_srem.password2': None,
'socle.schema_schema2.databases.user_database_srep.name': None,
'socle.schema_schema2.databases.user_database_srep.login': None,
'socle.schema_schema2.databases.user_database_srep.password2': None,
'socle.schema_schema3.database_names': ['srep',
'snom',
'srem'],
'socle.schema_schema3.databases.password': None,
'socle.schema_schema3.databases.user_database_snom.name': None,
'socle.schema_schema3.databases.user_database_snom.login': None,
'socle.schema_schema3.databases.user_database_snom.password2': None,
'socle.schema_schema3.databases.user_database_srem.name': None,
'socle.schema_schema3.databases.user_database_srem.login': None,
'socle.schema_schema3.databases.user_database_srem.password2': None,
'socle.schema_schema3.databases.user_database_srep.name': None,
'socle.schema_schema3.databases.user_database_srep.login': None,
'socle.schema_schema3.databases.user_database_srep.password2': None,
}
#
assert [opt.path() for opt in cfg.value.mandatory()] == ['socle.schema_schema1.databases.password',
'socle.schema_schema1.databases.user_database_srep.name',
'socle.schema_schema1.databases.user_database_srep.login',
'socle.schema_schema1.databases.user_database_srep.password2',
'socle.schema_schema1.databases.user_database_snom.name',
'socle.schema_schema1.databases.user_database_snom.login',
'socle.schema_schema1.databases.user_database_snom.password2',
'socle.schema_schema1.databases.user_database_srem.name',
'socle.schema_schema1.databases.user_database_srem.login',
'socle.schema_schema1.databases.user_database_srem.password2',
'socle.schema_schema2.databases.password',
'socle.schema_schema2.databases.user_database_srep.name',
'socle.schema_schema2.databases.user_database_srep.login',
'socle.schema_schema2.databases.user_database_srep.password2',
'socle.schema_schema2.databases.user_database_snom.name',
'socle.schema_schema2.databases.user_database_snom.login',
'socle.schema_schema2.databases.user_database_snom.password2',
'socle.schema_schema2.databases.user_database_srem.name',
'socle.schema_schema2.databases.user_database_srem.login',
'socle.schema_schema2.databases.user_database_srem.password2',
'socle.schema_schema3.databases.password',
'socle.schema_schema3.databases.user_database_srep.name',
'socle.schema_schema3.databases.user_database_srep.login',
'socle.schema_schema3.databases.user_database_srep.password2',
'socle.schema_schema3.databases.user_database_snom.name',
'socle.schema_schema3.databases.user_database_snom.login',
'socle.schema_schema3.databases.user_database_snom.password2',
'socle.schema_schema3.databases.user_database_srem.name',
'socle.schema_schema3.databases.user_database_srem.login',
'socle.schema_schema3.databases.user_database_srem.password2',
]
#
cfg.option('socle.schema_schema2.database_names').value.set(['another'])
assert cfg.value.get() == {'socle.database_schemas': ['schema1',
'schema2',
'schema3'],
'socle.schema_schema1.database_names': ['srep',
'snom',
'srem'],
'socle.schema_schema1.databases.password': None,
'socle.schema_schema1.databases.user_database_snom.name': None,
'socle.schema_schema1.databases.user_database_snom.login': None,
'socle.schema_schema1.databases.user_database_snom.password2': None,
'socle.schema_schema1.databases.user_database_srem.name': None,
'socle.schema_schema1.databases.user_database_srem.login': None,
'socle.schema_schema1.databases.user_database_srem.password2': None,
'socle.schema_schema1.databases.user_database_srep.name': None,
'socle.schema_schema1.databases.user_database_srep.login': None,
'socle.schema_schema1.databases.user_database_srep.password2': None,
'socle.schema_schema2.database_names': ['another'],
'socle.schema_schema2.databases.password': None,
'socle.schema_schema2.databases.user_database_another.name': None,
'socle.schema_schema2.databases.user_database_another.login': None,
'socle.schema_schema2.databases.user_database_another.password2': None,
'socle.schema_schema3.database_names': ['srep',
'snom',
'srem'],
'socle.schema_schema3.databases.password': None,
'socle.schema_schema3.databases.user_database_snom.name': None,
'socle.schema_schema3.databases.user_database_snom.login': None,
'socle.schema_schema3.databases.user_database_snom.password2': None,
'socle.schema_schema3.databases.user_database_srem.name': None,
'socle.schema_schema3.databases.user_database_srem.login': None,
'socle.schema_schema3.databases.user_database_srem.password2': None,
'socle.schema_schema3.databases.user_database_srep.name': None,
'socle.schema_schema3.databases.user_database_srep.login': None,
'socle.schema_schema3.databases.user_database_srep.password2': None,
}
#
cfg.option('socle.database_schemas').value.set(['schema1'])
assert cfg.value.get() == {'socle.database_schemas': ['schema1'],
'socle.schema_schema1.database_names': ['srep',
'snom',
'srem'],
'socle.schema_schema1.databases.password': None,
'socle.schema_schema1.databases.user_database_snom.name': None,
'socle.schema_schema1.databases.user_database_snom.login': None,
'socle.schema_schema1.databases.user_database_snom.password2': None,
'socle.schema_schema1.databases.user_database_srem.name': None,
'socle.schema_schema1.databases.user_database_srem.login': None,
'socle.schema_schema1.databases.user_database_srem.password2': None,
'socle.schema_schema1.databases.user_database_srep.name': None,
'socle.schema_schema1.databases.user_database_srep.login': None,
'socle.schema_schema1.databases.user_database_srep.password2': None,
}
#
cfg.option('socle.schema_schema1.databases.password').value.set('password')
cfg.option('socle.schema_schema1.databases.user_database_snom.name').value.set('name1')
cfg.option('socle.schema_schema1.databases.user_database_srem.name').value.set('name2')
cfg.option('socle.schema_schema1.databases.user_database_srep.name').value.set('name3')
assert cfg.value.get() == {'socle.database_schemas': ['schema1'],
'socle.schema_schema1.database_names': ['srep',
'snom',
'srem'],
'socle.schema_schema1.databases.password': 'password',
'socle.schema_schema1.databases.user_database_snom.login': 'name1',
'socle.schema_schema1.databases.user_database_snom.name': 'name1',
'socle.schema_schema1.databases.user_database_snom.password2': 'password',
'socle.schema_schema1.databases.user_database_srem.login': 'name2',
'socle.schema_schema1.databases.user_database_srem.name': 'name2',
'socle.schema_schema1.databases.user_database_srem.password2': 'password',
'socle.schema_schema1.databases.user_database_srep.login': 'name3',
'socle.schema_schema1.databases.user_database_srep.name': 'name3',
'socle.schema_schema1.databases.user_database_srep.password2': 'password',
}
assert [opt.path() for opt in cfg.value.mandatory()] == []
#
cfg.option('socle.schema_schema1.database_names').value.set(['snom'])
assert cfg.value.get() == {'socle.database_schemas': ['schema1'],
'socle.schema_schema1.database_names': ['snom'],
'socle.schema_schema1.databases.password': 'password',
'socle.schema_schema1.databases.user_database_snom.login': 'name1',
'socle.schema_schema1.databases.user_database_snom.name': 'name1',
'socle.schema_schema1.databases.user_database_snom.password2': 'password',
}
assert [opt.path() for opt in cfg.value.mandatory()] == []
def test_dyn_link_subdyn_tree():
password = StrOption(name="password", doc="password", properties=('mandatory',))
name = StrOption(name="name", doc="name", properties=('mandatory',))
login = StrOption(name="login", doc="login", default=Calculation(calc_value, Params((ParamOption(name)))), properties=('mandatory',))
password2 = StrOption(name="password2", doc="password2", default=Calculation(calc_value, Params((ParamOption(password)))), properties=('mandatory',))
user_names = StrOption(name="users", doc="users", multi=True, default=["user1"])
user_database = DynOptionDescription(name="user_database_", doc="user database", suffixes=Calculation(calc_value, Params((ParamOption(user_names, notraisepropertyerror=True)))), children=[name, login, password2])
database_names = StrOption(name="database_names", doc="database_names", multi=True, default=["srep"])
databases = DynOptionDescription(name="db_", doc="database", suffixes=Calculation(calc_value, Params((ParamOption(database_names, notraisepropertyerror=True)))), children=[user_names, password, user_database])
schema_names = StrOption(name="database_schemas", doc="database_schemas", multi=True, default=["schema1"])
schema = DynOptionDescription(name="schema_", doc="schema_", suffixes=Calculation(calc_value, Params((ParamOption(schema_names, notraisepropertyerror=True)))), children=[database_names, databases])
socle = OptionDescription(name="socle", doc="socle", children=[schema, schema_names])
root = OptionDescription(name="baseoption", doc="baseoption", children=[socle])
cfg = Config(root)
assert [opt.path() for opt in cfg.value.mandatory()] == ['socle.schema_schema1.db_srep.password',
'socle.schema_schema1.db_srep.user_database_user1.name',
'socle.schema_schema1.db_srep.user_database_user1.login',
'socle.schema_schema1.db_srep.user_database_user1.password2',
]
#
cfg.option('socle.schema_schema1.db_srep.user_database_user1.name').value.set('name')
assert [opt.path() for opt in cfg.value.mandatory()] == ['socle.schema_schema1.db_srep.password',
'socle.schema_schema1.db_srep.user_database_user1.password2',
]
#
cfg.option('socle.schema_schema1.db_srep.password').value.set('password')
assert [opt.path() for opt in cfg.value.mandatory()] == []
assert cfg.value.get() == {'socle.database_schemas': ['schema1'],
'socle.schema_schema1.database_names': ['srep'],
'socle.schema_schema1.db_srep.password': 'password',
'socle.schema_schema1.db_srep.user_database_user1.login': 'name',
'socle.schema_schema1.db_srep.user_database_user1.name': 'name',
'socle.schema_schema1.db_srep.user_database_user1.password2': 'password',
'socle.schema_schema1.db_srep.users': ['user1'],
}
#
cfg.option('socle.schema_schema1.db_srep.users').value.set(['user1', 'user2'])
assert cfg.value.get() == {'socle.database_schemas': ['schema1'],
'socle.schema_schema1.database_names': ['srep'],
'socle.schema_schema1.db_srep.password': 'password',
'socle.schema_schema1.db_srep.user_database_user1.login': 'name',
'socle.schema_schema1.db_srep.user_database_user1.name': 'name',
'socle.schema_schema1.db_srep.user_database_user1.password2': 'password',
'socle.schema_schema1.db_srep.user_database_user2.login': None,
'socle.schema_schema1.db_srep.user_database_user2.name': None,
'socle.schema_schema1.db_srep.user_database_user2.password2': 'password',
'socle.schema_schema1.db_srep.users': ['user1', 'user2'],
}
#
cfg.option('socle.schema_schema1.db_srep.users').value.set([])
assert cfg.value.get() == {'socle.database_schemas': ['schema1'],
'socle.schema_schema1.database_names': ['srep'],
'socle.schema_schema1.db_srep.password': 'password',
'socle.schema_schema1.db_srep.users': [],
}
#
cfg.option('socle.schema_schema1.database_names').value.set([])
assert cfg.value.get() == {'socle.database_schemas': ['schema1'],
'socle.schema_schema1.database_names': [],
}
#
cfg.option('socle.database_schemas').value.set([])
assert cfg.value.get() == {'socle.database_schemas': [],
}
#
cfg.option('socle.database_schemas').value.reset()
cfg.option('socle.schema_schema1.database_names').value.reset()
cfg.option('socle.schema_schema1.db_srep.users').value.reset()
assert cfg.value.get() == {'socle.database_schemas': ['schema1'],
'socle.schema_schema1.database_names': ['srep'],
'socle.schema_schema1.db_srep.password': 'password',
'socle.schema_schema1.db_srep.user_database_user1.login': 'name',
'socle.schema_schema1.db_srep.user_database_user1.name': 'name',
'socle.schema_schema1.db_srep.user_database_user1.password2': 'password',
'socle.schema_schema1.db_srep.users': ['user1'],
}
def test_dyn_link_subdyn_same_variable():
password = StrOption(name="password", doc="password", properties=('mandatory',))
name = StrOption(name="name", doc="name", properties=('mandatory',))
login = StrOption(name="login", doc="login", default=Calculation(calc_value, Params((ParamOption(name)))), properties=('mandatory',))
password2 = StrOption(name="password2", doc="password2", default=Calculation(calc_value, Params((ParamOption(password)))), properties=('mandatory',))
schema_names = StrOption(name="database_schemas", doc="database_schemas", multi=True, default=["schema1"])
user_database = DynOptionDescription(name="user_database_", doc="user database", suffixes=Calculation(calc_value, Params((ParamOption(schema_names, notraisepropertyerror=True)))), children=[name, login, password2])
databases = DynOptionDescription(name="db_", doc="database", suffixes=Calculation(calc_value, Params((ParamOption(schema_names, notraisepropertyerror=True)))), children=[password, user_database])
schema = DynOptionDescription(name="schema_", doc="schema_", suffixes=Calculation(calc_value, Params((ParamOption(schema_names, notraisepropertyerror=True)))), children=[databases])
socle = OptionDescription(name="socle", doc="socle", children=[schema, schema_names])
root = OptionDescription(name="baseoption", doc="baseoption", children=[socle])
cfg = Config(root)
assert [opt.path() for opt in cfg.value.mandatory()] == ['socle.schema_schema1.db_schema1.password',
'socle.schema_schema1.db_schema1.user_database_schema1.name',
'socle.schema_schema1.db_schema1.user_database_schema1.login',
'socle.schema_schema1.db_schema1.user_database_schema1.password2',
]
#
cfg.option('socle.schema_schema1.db_schema1.user_database_schema1.name').value.set('name')
assert [opt.path() for opt in cfg.value.mandatory()] == ['socle.schema_schema1.db_schema1.password',
'socle.schema_schema1.db_schema1.user_database_schema1.password2',
]
#
cfg.option('socle.schema_schema1.db_schema1.password').value.set('password')
cfg.option('socle.schema_schema1.db_schema1.user_database_schema1.name').value.set('name')
assert [opt.path() for opt in cfg.value.mandatory()] == []
assert cfg.value.get() == {'socle.database_schemas': ['schema1'],
'socle.schema_schema1.db_schema1.password': 'password',
'socle.schema_schema1.db_schema1.user_database_schema1.login': 'name',
'socle.schema_schema1.db_schema1.user_database_schema1.name': 'name',
'socle.schema_schema1.db_schema1.user_database_schema1.password2': 'password',
}
#
cfg.option('socle.database_schemas').value.set(['schema1', 'schema2'])
assert [opt.path() for opt in cfg.value.mandatory()] == ['socle.schema_schema1.db_schema1.user_database_schema2.name',
'socle.schema_schema1.db_schema1.user_database_schema2.login',
'socle.schema_schema1.db_schema2.password',
'socle.schema_schema1.db_schema2.user_database_schema1.name',
'socle.schema_schema1.db_schema2.user_database_schema1.login',
'socle.schema_schema1.db_schema2.user_database_schema1.password2',
'socle.schema_schema1.db_schema2.user_database_schema2.name',
'socle.schema_schema1.db_schema2.user_database_schema2.login',
'socle.schema_schema1.db_schema2.user_database_schema2.password2',
'socle.schema_schema2.db_schema1.password',
'socle.schema_schema2.db_schema1.user_database_schema1.name',
'socle.schema_schema2.db_schema1.user_database_schema1.login',
'socle.schema_schema2.db_schema1.user_database_schema1.password2',
'socle.schema_schema2.db_schema1.user_database_schema2.name',
'socle.schema_schema2.db_schema1.user_database_schema2.login',
'socle.schema_schema2.db_schema1.user_database_schema2.password2',
'socle.schema_schema2.db_schema2.password',
'socle.schema_schema2.db_schema2.user_database_schema1.name',
'socle.schema_schema2.db_schema2.user_database_schema1.login',
'socle.schema_schema2.db_schema2.user_database_schema1.password2',
'socle.schema_schema2.db_schema2.user_database_schema2.name',
'socle.schema_schema2.db_schema2.user_database_schema2.login',
'socle.schema_schema2.db_schema2.user_database_schema2.password2',
]
assert cfg.value.get() == {'socle.database_schemas': ['schema1', 'schema2'],
'socle.schema_schema1.db_schema1.password': 'password',
'socle.schema_schema1.db_schema1.user_database_schema1.login': 'name',
'socle.schema_schema1.db_schema1.user_database_schema1.name': 'name',
'socle.schema_schema1.db_schema1.user_database_schema1.password2': 'password',
'socle.schema_schema1.db_schema1.user_database_schema2.login': None,
'socle.schema_schema1.db_schema1.user_database_schema2.name': None,
'socle.schema_schema1.db_schema1.user_database_schema2.password2': 'password',
'socle.schema_schema1.db_schema2.password': None,
'socle.schema_schema1.db_schema2.user_database_schema1.login': None,
'socle.schema_schema1.db_schema2.user_database_schema1.name': None,
'socle.schema_schema1.db_schema2.user_database_schema1.password2': None,
'socle.schema_schema1.db_schema2.user_database_schema2.login': None,
'socle.schema_schema1.db_schema2.user_database_schema2.name': None,
'socle.schema_schema1.db_schema2.user_database_schema2.password2': None,
'socle.schema_schema2.db_schema1.password': None,
'socle.schema_schema2.db_schema1.user_database_schema1.login': None,
'socle.schema_schema2.db_schema1.user_database_schema1.name': None,
'socle.schema_schema2.db_schema1.user_database_schema1.password2': None,
'socle.schema_schema2.db_schema1.user_database_schema2.login': None,
'socle.schema_schema2.db_schema1.user_database_schema2.name': None,
'socle.schema_schema2.db_schema1.user_database_schema2.password2': None,
'socle.schema_schema2.db_schema2.password': None,
'socle.schema_schema2.db_schema2.user_database_schema1.login': None,
'socle.schema_schema2.db_schema2.user_database_schema1.name': None,
'socle.schema_schema2.db_schema2.user_database_schema1.password2': None,
'socle.schema_schema2.db_schema2.user_database_schema2.login': None,
'socle.schema_schema2.db_schema2.user_database_schema2.name': None,
'socle.schema_schema2.db_schema2.user_database_schema2.password2': None,
}
assert cfg.option('socle.schema_schema1.db_schema1.user_database_schema1').value.get() == {
'socle.schema_schema1.db_schema1.user_database_schema1.login': 'name',
'socle.schema_schema1.db_schema1.user_database_schema1.name': 'name',
'socle.schema_schema1.db_schema1.user_database_schema1.password2': 'password',
}
def test_dyn_link_subdyn_disabled():
password = StrOption(name="password", doc="password")
name = StrOption(name="name", doc="name")
login = StrOption(name="login", doc="login", default=Calculation(calc_value, Params((ParamOption(name)))))
disabled_property = Calculation(calc_value,
Params(ParamValue('disabled'),
kwargs={'condition': ParamOption(login),
'expected': ParamValue('name'),
'default': ParamValue(None)}))
password2 = StrOption(name="password2", doc="password2", default=Calculation(calc_value, Params((ParamOption(password)))), properties=(disabled_property,))
schema_names = StrOption(name="database_schemas", doc="database_schemas", multi=True, default=["schema1"])
user_database = DynOptionDescription(name="user_database_", doc="user database", suffixes=Calculation(calc_value, Params((ParamOption(schema_names, notraisepropertyerror=True)))), children=[name, login, password2])
databases = DynOptionDescription(name="db_", doc="database", suffixes=Calculation(calc_value, Params((ParamOption(schema_names, notraisepropertyerror=True)))), children=[password, user_database])
schema = DynOptionDescription(name="schema_", doc="schema_", suffixes=Calculation(calc_value, Params((ParamOption(schema_names, notraisepropertyerror=True)))), children=[databases])
socle = OptionDescription(name="socle", doc="socle", children=[schema, schema_names])
root = OptionDescription(name="baseoption", doc="baseoption", children=[socle])
cfg = Config(root)
cfg.property.read_write()
assert [opt.path() for opt in cfg.value.mandatory()] == []
assert cfg.value.get() == {'socle.database_schemas': ['schema1'],
'socle.schema_schema1.db_schema1.password': None,
'socle.schema_schema1.db_schema1.user_database_schema1.login': None,
'socle.schema_schema1.db_schema1.user_database_schema1.name': None,
'socle.schema_schema1.db_schema1.user_database_schema1.password2': None,
}
#
cfg.option('socle.schema_schema1.db_schema1.user_database_schema1.name').value.set('name')
assert cfg.value.get() == {'socle.database_schemas': ['schema1'],
'socle.schema_schema1.db_schema1.password': None,
'socle.schema_schema1.db_schema1.user_database_schema1.login': 'name',
'socle.schema_schema1.db_schema1.user_database_schema1.name': 'name',
}
#
cfg.option('socle.database_schemas').value.set(['schema1', 'schema2'])
cfg.option('socle.schema_schema2.db_schema2.user_database_schema2.name').value.set('name2')
assert cfg.value.get() == {'socle.database_schemas': ['schema1', 'schema2'],
'socle.schema_schema1.db_schema1.password': None,
'socle.schema_schema1.db_schema1.user_database_schema1.login': 'name',
'socle.schema_schema1.db_schema1.user_database_schema1.name': 'name',
'socle.schema_schema1.db_schema1.user_database_schema2.login': None,
'socle.schema_schema1.db_schema1.user_database_schema2.name': None,
'socle.schema_schema1.db_schema1.user_database_schema2.password2': None,
'socle.schema_schema1.db_schema2.password': None,
'socle.schema_schema1.db_schema2.user_database_schema1.login': None,
'socle.schema_schema1.db_schema2.user_database_schema1.name': None,
'socle.schema_schema1.db_schema2.user_database_schema1.password2': None,
'socle.schema_schema1.db_schema2.user_database_schema2.login': None,
'socle.schema_schema1.db_schema2.user_database_schema2.name': None,
'socle.schema_schema1.db_schema2.user_database_schema2.password2': None,
'socle.schema_schema2.db_schema1.password': None,
'socle.schema_schema2.db_schema1.user_database_schema1.login': None,
'socle.schema_schema2.db_schema1.user_database_schema1.name': None,
'socle.schema_schema2.db_schema1.user_database_schema1.password2': None,
'socle.schema_schema2.db_schema1.user_database_schema2.login': None,
'socle.schema_schema2.db_schema1.user_database_schema2.name': None,
'socle.schema_schema2.db_schema1.user_database_schema2.password2': None,
'socle.schema_schema2.db_schema2.password': None,
'socle.schema_schema2.db_schema2.user_database_schema1.login': None,
'socle.schema_schema2.db_schema2.user_database_schema1.name': None,
'socle.schema_schema2.db_schema2.user_database_schema1.password2': None,
'socle.schema_schema2.db_schema2.user_database_schema2.login': 'name2',
'socle.schema_schema2.db_schema2.user_database_schema2.name': 'name2',
'socle.schema_schema2.db_schema2.user_database_schema2.password2': None,
}

View file

@ -146,23 +146,23 @@ def test_force_default_on_freeze_multi():
# assert not list_sessions() # assert not list_sessions()
def test_force_default_on_freeze_leader(): #def test_force_default_on_freeze_leader():
dummy1 = BoolOption('dummy1', 'Test int option', multi=True, properties=('force_default_on_freeze',)) # dummy1 = BoolOption('dummy1', 'Test int option', multi=True, properties=('force_default_on_freeze',))
dummy2 = BoolOption('dummy2', 'Test string option', multi=True) # dummy2 = BoolOption('dummy2', 'Test string option', multi=True)
descr = Leadership("dummy1", "", [dummy1, dummy2]) # descr = Leadership("dummy1", "", [dummy1, dummy2])
od1 = OptionDescription("root", "", [descr]) # od1 = OptionDescription("root", "", [descr])
with pytest.raises(ConfigError): # with pytest.raises(ConfigError):
Config(od1) # Config(od1)
# assert not list_sessions() # assert not list_sessions()
def test_force_metaconfig_on_freeze_leader(): #def test_force_metaconfig_on_freeze_leader():
dummy1 = BoolOption('dummy1', 'Test int option', multi=True, properties=('force_metaconfig_on_freeze',)) # dummy1 = BoolOption('dummy1', 'Test int option', multi=True, properties=('force_metaconfig_on_freeze',))
dummy2 = BoolOption('dummy2', 'Test string option', multi=True) # dummy2 = BoolOption('dummy2', 'Test string option', multi=True)
descr = Leadership("dummy1", "", [dummy1, dummy2]) # descr = Leadership("dummy1", "", [dummy1, dummy2])
od1 = OptionDescription("root", "", [descr]) # od1 = OptionDescription("root", "", [descr])
with pytest.raises(ConfigError): # with pytest.raises(ConfigError):
Config(od1) # Config(od1)
# assert not list_sessions() # assert not list_sessions()

View file

@ -458,13 +458,12 @@ class TiramisuOptionProperty(CommonTiramisuOption):
): ):
"""Get properties for an option""" """Get properties for an option"""
option_bag = options_bag[-1] option_bag = options_bag[-1]
if not only_raises:
return option_bag.properties
settings = self._config_bag.context.get_settings() settings = self._config_bag.context.get_settings()
ret = settings.calc_raises_properties(option_bag, if not only_raises:
return settings.getproperties(option_bag)
return settings.calc_raises_properties(option_bag,
uncalculated=uncalculated, uncalculated=uncalculated,
) )
return ret
@option_type(['option', 'optiondescription', 'with_or_without_index']) @option_type(['option', 'optiondescription', 'with_or_without_index'])
def add(self, def add(self,
@ -491,8 +490,9 @@ class TiramisuOptionProperty(CommonTiramisuOption):
): ):
"""Remove new property for an option""" """Remove new property for an option"""
option_bag = options_bag[-1] option_bag = options_bag[-1]
props = option_bag.properties settings = self._config_bag.context.get_settings()
self._config_bag.context.get_settings().setproperties(option_bag, props = settings.getproperties(option_bag)
settings.setproperties(option_bag,
props - {prop}, props - {prop},
) )

View file

@ -313,8 +313,8 @@ def manager_callback(callback: Callable,
# 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 param.notraisepropertyerror or param.raisepropertyerror: if param.notraisepropertyerror or param.raisepropertyerror:
raise err from err raise err from err
raise ConfigError(_('unable to carry out a calculation for "{}"' display_name = option_bag.option.impl_get_display_name()
', {}').format(option.impl_get_display_name(), err), err) from err raise ConfigError(_('unable to carry out a calculation for "{}", {}').format(display_name, err)) from err
except ValueError as err: except ValueError as err:
raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(option_bag.option.impl_get_display_name(), err)) from err raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(option_bag.option.impl_get_display_name(), err)) from err
except AttributeError as err: except AttributeError as err:
@ -324,7 +324,8 @@ def manager_callback(callback: Callable,
['configerror'], ['configerror'],
config_bag.context.get_settings(), config_bag.context.get_settings(),
) )
raise ConfigError(_(f'unable to get value for calculating "{option_bag.option.impl_get_display_name()}", {err}')) from err display_name = option_bag.option.impl_get_display_name()
raise ConfigError(_(f'unable to get value for calculating "{display_name}", {err}')) from err
return value return value
def get_option_bag(config_bag, def get_option_bag(config_bag,
@ -359,8 +360,8 @@ def manager_callback(callback: Callable,
# 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 param.notraisepropertyerror or param.raisepropertyerror: if param.notraisepropertyerror or param.raisepropertyerror:
raise err from err raise err from err
raise ConfigError(_('unable to carry out a calculation for "{}"' display_name = option.impl_get_display_name()
', {}').format(option.impl_get_display_name(), err), err) from err raise ConfigError(_('unable to carry out a calculation for "{}", {}').format(display_name, err)) from err
except ValueError as err: except ValueError as err:
raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(option.impl_get_display_name(), err)) from err raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(option.impl_get_display_name(), err)) from err
except AttributeError as err: except AttributeError as err:
@ -370,7 +371,8 @@ def manager_callback(callback: Callable,
['configerror'], ['configerror'],
config_bag.context.get_settings(), config_bag.context.get_settings(),
) )
raise ConfigError(_(f'unable to get value for calculating "{option.impl_get_display_name()}", {err}')) from err display_name = option.impl_get_display_name()
raise ConfigError(_(f'unable to get value for calculating "{display_name}", {err}')) from err
if len(options_bag) > 1: if len(options_bag) > 1:
parent_option_bag = options_bag[-2] parent_option_bag = options_bag[-2]
else: else:
@ -399,17 +401,17 @@ def manager_callback(callback: Callable,
param.default_value, param.default_value,
) )
except ValueError as err: except ValueError as err:
raise ConfigError(_('option "{}" cannot be calculated: {}').format(option.impl_get_display_name(), display_name = option.impl_get_display_name()
str(err), raise ConfigError(_(f'unable to get value for calculating "{display_name}", {err}')) from err
))
if isinstance(param, ParamIndex): if isinstance(param, ParamIndex):
return index return index
if isinstance(param, ParamSuffix): if isinstance(param, ParamSuffix):
if not option.issubdyn(): if not option.issubdyn():
raise ConfigError(_('option "{}" is not in a dynoptiondescription').format(option.impl_get_display_name())) display_name = option_bag.option.impl_get_display_name()
return option.impl_getsuffix() raise ConfigError(_('option "{display_name}" is not in a dynoptiondescription'))
return option.get_suffixes()[-1]
if isinstance(param, ParamSelfOption): if isinstance(param, ParamSelfOption):
value = calc_self(param, value = calc_self(param,
@ -452,46 +454,26 @@ def manager_callback(callback: Callable,
raise ConfigError(_(f'option "{option.impl_get_display_name()}" is not in a dynoptiondescription: {err}')) raise ConfigError(_(f'option "{option.impl_get_display_name()}" is not in a dynoptiondescription: {err}'))
callbk_option = soptions_bag[-1].option callbk_option = soptions_bag[-1].option
found = True found = True
elif option.impl_is_sub_dyn_optiondescription():
if option.getsubdyn() == callbk_option.getsubdyn():
root_path = option.impl_getpath().rsplit('.', 1)[0]
len_path = root_path.count('.')
full_path = root_path + '.' + callbk_option.impl_getpath().split('.', len_path + 1)[-1]
root_option_bag = OptionBag(config_bag.context.get_description(),
None,
config_bag,
)
try:
soptions_bag = config_bag.context.get_sub_option_bag(root_option_bag,
full_path,
#FIXME index?
index=None,
validate_properties=True,
properties=None,
)
except AttributeError as err:
raise ConfigError(_(f'option "{option.impl_get_display_name()}" is not in a dynoptiondescription: {err}'))
callbk_option = soptions_bag[-1].option
found = True
elif option.impl_is_dynsymlinkoption(): elif option.impl_is_dynsymlinkoption():
rootpath = option.rootpath rootpath = option.rootpath
call_path = callbk_option.impl_getpath() call_path = callbk_option.impl_getpath()
if option.opt.issubdyn() and callbk_option.getsubdyn() == option.getsubdyn() or \ in_same_dyn = False
not option.opt.issubdyn() and callbk_option.getsubdyn() == option.opt: if not option.opt.issubdyn() and callbk_option.getsubdyn() == option.opt:
# in same dynoption # First dyn
suffix = option.impl_getsuffix() in_same_dyn = True
subdyn = callbk_option.getsubdyn() elif option.opt.issubdyn():
root_path, sub_path = subdyn.split_path(subdyn, # Search if callback and option has a common subdyn
option, callbk_subdyn = callbk_option.getsubdyn()
) sub_dyn = option
if root_path: while True:
parent_path = root_path + subdyn.impl_getname(suffix) + sub_path sub_dyn = sub_dyn.getsubdyn()
else: if sub_dyn == callbk_subdyn:
parent_path = subdyn.impl_getname(suffix) + sub_path in_same_dyn = True
callbk_option = callbk_option.to_dynoption(parent_path, break
suffix, if not sub_dyn.issubdyn():
subdyn, break
) if in_same_dyn:
callbk_option = callbk_option.to_sub_dyoption(option.get_suffixes())
found = True found = True
if not found: if not found:
callbk_options = [] callbk_options = []
@ -519,8 +501,6 @@ def manager_callback(callback: Callable,
else: else:
index_ = None index_ = None
with_index = False with_index = False
if callbk_option.impl_getpath() == 'od.dodval1.st.boolean':
raise Exception('pfff')
value = get_value(config_bag, value = get_value(config_bag,
callbk_option, callbk_option,
param, param,
@ -602,6 +582,7 @@ def carry_out_calculation(option,
kwargs, kwargs,
) )
if isinstance(ret, list) and not option.impl_is_dynoptiondescription() and \ if isinstance(ret, list) and not option.impl_is_dynoptiondescription() and \
not option.impl_is_optiondescription() and \
option.impl_is_follower() and not option.impl_is_submulti(): option.impl_is_follower() and not option.impl_is_submulti():
if args or kwargs: if args or kwargs:
raise LeadershipError(_('the "{}" function with positional arguments "{}" ' raise LeadershipError(_('the "{}" function with positional arguments "{}" '

View file

@ -27,7 +27,6 @@ from typing import Optional, List, Any, Union
from .error import PropertiesOptionError, ConfigError, ConflictError, \ from .error import PropertiesOptionError, ConfigError, ConflictError, \
LeadershipError LeadershipError
from .option import DynOptionDescription, Leadership, Option from .option import DynOptionDescription, Leadership, Option
from .option.syndynoptiondescription import SubDynOptionDescription
from .setting import OptionBag, ConfigBag, Settings, undefined, groups from .setting import OptionBag, ConfigBag, Settings, undefined, groups
from .value import Values, owners from .value import Values, owners
from .i18n import _ from .i18n import _
@ -164,6 +163,16 @@ class _SubConfig:
) )
except AttributeError as err: except AttributeError as err:
raise ConfigError(_(f'option "{option.impl_get_display_name()}" is not in a dynoptiondescription: {err}')) raise ConfigError(_(f'option "{option.impl_get_display_name()}" is not in a dynoptiondescription: {err}'))
if options_bag[-1].option.impl_is_dynoptiondescription():
for suffix in options_bag[-1].option.get_suffixes(config_bag, dynoption=options_bag[-2].option):
dynopt = options_bag[-1].option.to_dynoption(options_bag[-2].path,
options_bag[-2].option._suffixes + [suffix],
)
doption_bag = OptionBag(dynopt, None, option_bag.config_bag)
self.reset_one_option_cache(resetted_opts,
doption_bag,
)
else:
self._reset_cache_dyn_optiondescription(options_bag[-1], self._reset_cache_dyn_optiondescription(options_bag[-1],
resetted_opts, resetted_opts,
) )
@ -182,18 +191,37 @@ class _SubConfig:
# it's an option in dynoptiondescription, remove cache for all generated option # it's an option in dynoptiondescription, remove cache for all generated option
config_bag = option_bag.config_bag config_bag = option_bag.config_bag
options = [soption_bag] options = [soption_bag]
for wdynopt in reversed(option.get_sub_dyns()): dynopt = option.get_sub_dyns()[-1]()
dynopt = wdynopt() dyn_path = dynopt.impl_getpath()
sub_options = [] if '.' in dyn_path:
for sub_option in options: root_path = dyn_path.rsplit('.', 1)[0]
sub_options.extend(dynopt.get_sub_children(sub_option.option, else:
root_path = ''
for suffix in dynopt.get_suffixes(config_bag):
suffix_dynopt = dynopt.to_dynoption(root_path,
[suffix],
)
soption_bag = OptionBag(suffix_dynopt, None, config_bag)
for data in self.walk(soption_bag, validate_properties=False):
if isinstance(data, dict):
leader = data.pop('leader')
resetted_opts.append(leader.path)
leader.option.reset_cache(leader.path,
config_bag, config_bag,
properties=None, resetted_opts,
)) )
options = sub_options for followers in data.values():
for doption_bag in options: for follower in followers:
self.reset_one_option_cache(resetted_opts, resetted_opts.append(follower.path)
doption_bag, follower.option.reset_cache(follower.path,
config_bag,
resetted_opts,
)
else:
resetted_opts.append(data.path)
data.option.reset_cache(data.path,
config_bag,
resetted_opts,
) )
else: else:
self.reset_one_option_cache(resetted_opts, self.reset_one_option_cache(resetted_opts,
@ -235,12 +263,7 @@ class _SubConfig:
option_bag, option_bag,
resetted_opts, resetted_opts,
): ):
option = option_bag.option for doption_bag in option_bag.option.get_sub_children(option_bag.option,
if isinstance(option, (DynOptionDescription, SubDynOptionDescription)):
dynoption = option
else:
dynoption = option.getsubdyn()
for doption_bag in dynoption.get_sub_children(option,
option_bag.config_bag, option_bag.config_bag,
index=option_bag.index, index=option_bag.index,
properties=None properties=None
@ -338,11 +361,13 @@ class _SubConfig:
def walk(self, def walk(self,
option_bag: OptionBag, option_bag: OptionBag,
*,
types: List[str]=('option',), types: List[str]=('option',),
group_type=None, group_type=None,
recursive: bool=True, recursive: bool=True,
walked: bool=False, walked: bool=False,
flatten_leadership: bool=False, flatten_leadership: bool=False,
validate_properties: bool=True,
): ):
"""walk to tree """walk to tree
""" """
@ -362,13 +387,14 @@ class _SubConfig:
yield from self.walk(self.get_sub_option_bag(option_bag, # pylint: disable=no-member yield from self.walk(self.get_sub_option_bag(option_bag, # pylint: disable=no-member
opt.impl_getpath(), opt.impl_getpath(),
None, None,
True, validate_properties,
follower_not_apply_requires=flatten_leadership, follower_not_apply_requires=flatten_leadership,
)[-1], )[-1],
types=types, types=types,
recursive=recursive, recursive=recursive,
group_type=group_type, group_type=group_type,
walked=True, walked=True,
validate_properties=validate_properties,
) )
except PropertiesOptionError as err: except PropertiesOptionError as err:
if err.proptype in (['mandatory'], ['empty']): if err.proptype in (['mandatory'], ['empty']):
@ -380,7 +406,7 @@ class _SubConfig:
leader_option_bag = self.get_sub_option_bag(option_bag, # pylint: disable=no-member leader_option_bag = self.get_sub_option_bag(option_bag, # pylint: disable=no-member
leader.impl_getpath(), leader.impl_getpath(),
None, None,
True, validate_properties,
)[-1] )[-1]
followers_dict = {'leader': leader_option_bag} followers_dict = {'leader': leader_option_bag}
values = self.get_value(leader_option_bag, values = self.get_value(leader_option_bag,
@ -403,7 +429,7 @@ class _SubConfig:
options_bag = self.get_sub_option_bag(option_bag, # pylint: disable=no-member options_bag = self.get_sub_option_bag(option_bag, # pylint: disable=no-member
follower_path, follower_path,
idx, idx,
True, validate_properties,
leadership_length=ls_length, leadership_length=ls_length,
) )
for f_follower_bag in self.walk(options_bag[-1], for f_follower_bag in self.walk(options_bag[-1],
@ -411,6 +437,7 @@ class _SubConfig:
recursive=recursive, recursive=recursive,
group_type=group_type, group_type=group_type,
walked=True, walked=True,
validate_properties=validate_properties,
): ):
if 'mandatory' in types: if 'mandatory' in types:
yield f_follower_bag yield f_follower_bag
@ -576,7 +603,7 @@ class _CommonConfig(_SubConfig):
def _impl_build_all_caches(self, descr): def _impl_build_all_caches(self, descr):
if not descr.impl_already_build_caches(): if not descr.impl_already_build_caches():
descr._group_type = groups.root # pylint: disable=protected-access descr._group_type = groups.root # pylint: disable=protected-access
descr._build_cache(display_name=self._display_name) # pylint: disable=no-member,protected-access descr._build_cache(self._display_name) # pylint: disable=no-member,protected-access
if not hasattr(descr, '_cache_force_store_values'): if not hasattr(descr, '_cache_force_store_values'):
raise ConfigError(_('option description seems to be part of an other ' raise ConfigError(_('option description seems to be part of an other '
'config')) 'config'))
@ -727,8 +754,8 @@ class _CommonConfig(_SubConfig):
path: str, path: str,
index: Optional[int], index: Optional[int],
validate_properties: bool, validate_properties: bool,
leadership_length: int=None,
*, *,
leadership_length: int=None,
properties=undefined, properties=undefined,
follower_not_apply_requires: bool=False, follower_not_apply_requires: bool=False,
allow_dynoption: bool=False, allow_dynoption: bool=False,
@ -755,13 +782,8 @@ class _CommonConfig(_SubConfig):
if not suboption.impl_is_optiondescription(): if not suboption.impl_is_optiondescription():
raise TypeError(f'{suboption.impl_getpath()} is not an optiondescription') raise TypeError(f'{suboption.impl_getpath()} is not an optiondescription')
if not idx and option_bag.option == self.get_description():
subpath = None
else:
subpath = suboption.impl_getpath()
option = suboption.get_child(step, option = suboption.get_child(step,
option_bag.config_bag, option_bag.config_bag,
subpath,
allow_dynoption=allow_dynoption, allow_dynoption=allow_dynoption,
) )
if idx == last_idx: if idx == last_idx:
@ -787,6 +809,9 @@ class _CommonConfig(_SubConfig):
option_index = None option_index = None
apply_requires = True apply_requires = True
option_properties = undefined option_properties = undefined
if option_properties is undefined and not validate_properties:
# not transitive property error
apply_requires = False
sub_option_bag = OptionBag(option, sub_option_bag = OptionBag(option,
option_index, option_index,
option_bag.config_bag, option_bag.config_bag,

View file

@ -40,8 +40,8 @@ def valid_name(name):
""" """
if not isinstance(name, str): if not isinstance(name, str):
return False return False
# if '.' in name: if '.' in name:
# return False return False
return True return True
@ -166,8 +166,7 @@ class Base:
def impl_is_readonly(self) -> str: def impl_is_readonly(self) -> str:
"""the option is readonly """the option is readonly
""" """
# _path is None when initialise SymLinkOption return hasattr(self, '_path')
return hasattr(self, '_path') and self._path is not None # pylint: disable=no-member
def impl_getproperties(self) -> FrozenSet[str]: def impl_getproperties(self) -> FrozenSet[str]:
"""get properties """get properties
@ -322,3 +321,34 @@ class BaseOption(Base):
"""get dependencies information """get dependencies information
""" """
return getattr(self, '_dependencies_information', {}) return getattr(self, '_dependencies_information', {})
def to_sub_dyoption(self,
suffixes: list[str],
):
sub_dyn = self
# retrieve all subdyn options
sub_dyns = []
while True:
sub_dyn = sub_dyn.getsubdyn()
sub_dyns.append(sub_dyn)
if not sub_dyn.issubdyn():
break
paths = []
parent_path = self.impl_getpath().rsplit('.', 1)[0]
suffix_idx = len(sub_dyns) - 1
for sub_dyn in sub_dyns:
dyn_path = sub_dyn.impl_getpath()
if dyn_path.count('.') == parent_path.count('.'):
*root_paths, dyn_path_ = parent_path.split('.', dyn_path.count('.') + 1)
else:
*root_paths, dyn_path_, child_path = parent_path.split('.', dyn_path.count('.') + 1)
paths.insert(0, child_path)
paths.insert(0, sub_dyn.impl_getname(suffixes[suffix_idx]))
suffix_idx -= 1
parent_path = '.'.join(root_paths)
if parent_path:
paths.insert(0, parent_path)
full_parent_path = '.'.join(paths)
return self.to_dynoption(full_parent_path,
suffixes,
)

View file

@ -88,6 +88,7 @@ class DynOptionDescription(OptionDescription):
def get_suffixes(self, def get_suffixes(self,
config_bag: ConfigBag, config_bag: ConfigBag,
*,
dynoption=None, dynoption=None,
) -> List[str]: ) -> List[str]:
"""get dynamic suffixes """get dynamic suffixes
@ -134,8 +135,9 @@ class DynOptionDescription(OptionDescription):
(option.impl_is_sub_dyn_optiondescription() and option.opt == self) (option.impl_is_sub_dyn_optiondescription() and option.opt == self)
def split_path(self, def split_path(self,
dynoption,
option, option,
*,
dynoption=None,
) -> Tuple[str, str]: ) -> Tuple[str, str]:
"""self.impl_getpath() is something like root.xxx.dynoption_path """self.impl_getpath() is something like root.xxx.dynoption_path
option.impl_getpath() is something like root.xxx.dynoption_path.sub.path option.impl_getpath() is something like root.xxx.dynoption_path.sub.path
@ -169,8 +171,8 @@ class DynOptionDescription(OptionDescription):
properties=undefined, properties=undefined,
dynoption=None, dynoption=None,
): ):
root_path, sub_path = self.split_path(dynoption, root_path, sub_path = self.split_path(option,
option, dynoption=dynoption,
) )
for suffix in self.get_suffixes(config_bag, for suffix in self.get_suffixes(config_bag,
dynoption=dynoption, dynoption=dynoption,
@ -182,8 +184,7 @@ class DynOptionDescription(OptionDescription):
else: else:
parent_path = self.impl_getname(suffix) + sub_path parent_path = self.impl_getname(suffix) + sub_path
yield OptionBag(option.to_dynoption(parent_path, yield OptionBag(option.to_dynoption(parent_path,
suffix, [suffix],
self,
), ),
index, index,
config_bag, config_bag,

View file

@ -248,11 +248,9 @@ class Leadership(OptionDescription):
def to_dynoption(self, def to_dynoption(self,
rootpath: str, rootpath: str,
suffix: str, suffixes: Optional[list],
ori_dyn,
) -> SynDynLeadership: ) -> SynDynLeadership:
return SynDynLeadership(self, return SynDynLeadership(self,
rootpath, rootpath,
suffix, suffixes,
ori_dyn,
) )

View file

@ -464,15 +464,13 @@ class Option(BaseOption):
def to_dynoption(self, def to_dynoption(self,
rootpath: str, rootpath: str,
suffix: str, suffixes: list[str],
dyn_parent,
) -> SynDynOption: ) -> SynDynOption:
"""tranforme a dynoption to a syndynoption """tranforme a dynoption to a syndynoption
""" """
return SynDynOption(self, return SynDynOption(self,
rootpath, rootpath,
suffix, suffixes,
dyn_parent,
) )
def validate(self, value: Any): def validate(self, value: Any):
"""option needs a validate function """option needs a validate function

View file

@ -44,13 +44,13 @@ class CacheOptionDescription(BaseOption):
return self.impl_is_readonly() return self.impl_is_readonly()
def _build_cache(self, def _build_cache(self,
display_name,
_consistencies=None, _consistencies=None,
_consistencies_id=0, _consistencies_id=0,
currpath: List[str]=None, currpath: List[str]=None,
cache_option=None, cache_option=None,
force_store_values=None, force_store_values=None,
dependencies_information=None, dependencies_information=None,
display_name=None,
) -> None: ) -> None:
"""validate options and set option has readonly option """validate options and set option has readonly option
""" """
@ -80,13 +80,13 @@ class CacheOptionDescription(BaseOption):
subpath = '.'.join(sub_currpath) subpath = '.'.join(sub_currpath)
if isinstance(option, OptionDescription): if isinstance(option, OptionDescription):
# pylint: disable=protected-access # pylint: disable=protected-access
option._build_cache(_consistencies, option._build_cache(display_name,
_consistencies,
_consistencies_id, _consistencies_id,
sub_currpath, sub_currpath,
cache_option, cache_option,
force_store_values, force_store_values,
dependencies_information, dependencies_information,
display_name,
) )
else: else:
for information, options in option.get_dependencies_information().items(): for information, options in option.get_dependencies_information().items():
@ -96,15 +96,6 @@ class CacheOptionDescription(BaseOption):
properties = option.impl_getproperties() properties = option.impl_getproperties()
if 'force_store_value' in properties: if 'force_store_value' in properties:
force_store_values.append(option) force_store_values.append(option)
# if __debug__ and ('force_default_on_freeze' in properties or \
# 'force_metaconfig_on_freeze' in properties) and \
# 'frozen' not in properties and \
# option.impl_is_leader():
# raise ConfigError(_('a leader ({0}) cannot have '
# '"force_default_on_freeze" or '
# '"force_metaconfig_on_freeze" '
# 'property without "frozen"'
# '').format(option.impl_get_display_name()))
if option.impl_is_readonly(): if option.impl_is_readonly():
raise ConflictError(_('duplicate option: {0}').format(option)) raise ConflictError(_('duplicate option: {0}').format(option))
if not self.impl_is_readonly() and display_name: if not self.impl_is_readonly() and display_name:
@ -114,7 +105,7 @@ class CacheOptionDescription(BaseOption):
if init: if init:
self._cache_force_store_values = force_store_values # pylint: disable=attribute-defined-outside-init self._cache_force_store_values = force_store_values # pylint: disable=attribute-defined-outside-init
self._cache_dependencies_information = dependencies_information # pylint: disable=attribute-defined-outside-init self._cache_dependencies_information = dependencies_information # pylint: disable=attribute-defined-outside-init
self._path = self._name # pylint: disable=attribute-defined-outside-init,no-member self._path = None # pylint: disable=attribute-defined-outside-init,no-member
self._set_readonly() self._set_readonly()
def impl_build_force_store_values(self, def impl_build_force_store_values(self,
@ -146,10 +137,8 @@ class CacheOptionDescription(BaseOption):
leader_option_bag.properties = frozenset() leader_option_bag.properties = frozenset()
follower_len = len(values.get_value(leader_option_bag)[0]) follower_len = len(values.get_value(leader_option_bag)[0])
if option.issubdyn(): if option.issubdyn():
subpath = leader_option_bag.option.rootpath doption = option.to_dynoption(leader_option_bag.option.rootpath,
doption = option.to_dynoption(subpath, leader_option_bag.option.get_suffixes(),
leader_option_bag.option.impl_getsuffix(),
leader_option_bag.option.dyn_parent,
) )
else: else:
doption = option doption = option
@ -190,56 +179,48 @@ class OptionDescriptionWalk(CacheOptionDescription):
""" """
__slots__ = ('_children',) __slots__ = ('_children',)
def get_child_not_dynamic(self,
name,
allow_dynoption,
):
if name in self._children[0]: # pylint: disable=no-member
option = self._children[1][self._children[0].index(name)] # pylint: disable=no-member
if option.impl_is_dynoptiondescription() and not allow_dynoption:
raise AttributeError(_(f'unknown option "{name}" '
"in root optiondescription (it's a dynamic option)"
))
return option
def get_child(self, def get_child(self,
name: str, name: str,
config_bag: ConfigBag, config_bag: ConfigBag,
subpath: str,
*, *,
dynoption=None,
option_suffix: Optional[str]=None,
allow_dynoption: bool=False, allow_dynoption: bool=False,
) -> Union[BaseOption, SynDynOptionDescription]: ) -> Union[BaseOption, SynDynOptionDescription]:
"""get a child """get a child
""" """
# if not dyn # if not dyn
if name in self._children[0]: # pylint: disable=no-member option = self.get_child_not_dynamic(name,
option = self._children[1][self._children[0].index(name)] # pylint: disable=no-member allow_dynoption,
if option.impl_is_dynoptiondescription():
if allow_dynoption:
option_suffix = None
else:
raise AttributeError(_(f'unknown option "{name}" '
"in root optiondescription (it's a dynamic option)"
))
if option.issubdyn():
return option.to_dynoption(subpath,
option_suffix,
option,
) )
if option:
return option return option
# if dyn # if dyn
if dynoption:
self_opt = dynoption
else:
self_opt = self
for child in self._children[1]: # pylint: disable=no-member for child in self._children[1]: # pylint: disable=no-member
if not child.impl_is_dynoptiondescription(): if not child.impl_is_dynoptiondescription():
continue continue
for suffix in child.get_suffixes(config_bag, for suffix in child.get_suffixes(config_bag):
dynoption,
):
if name != child.impl_getname(suffix): if name != child.impl_getname(suffix):
continue continue
return child.to_dynoption(subpath, return child.to_dynoption(self.impl_getpath(),
suffix, [suffix],
child,
) )
if self.impl_get_group_type() == groups.root: # pylint: disable=no-member if self.impl_get_group_type() == groups.root: # pylint: disable=no-member
raise AttributeError(_(f'unknown option "{name}" ' raise AttributeError(_(f'unknown option "{name}" '
'in root optiondescription' 'in root optiondescription'
)) ))
raise AttributeError(_(f'unknown option "{name}" ' raise AttributeError(_(f'unknown option "{name}" '
f'in optiondescription "{self_opt.impl_get_display_name()}"' f'in optiondescription "{self.impl_get_display_name()}"'
)) ))
def get_children(self, def get_children(self,
@ -248,43 +229,54 @@ class OptionDescriptionWalk(CacheOptionDescription):
dyn: bool=True, dyn: bool=True,
#path: Optional[str]=None, #path: Optional[str]=None,
dynoption=None, dynoption=None,
option_suffix: Optional[str]=None,
) -> Union[BaseOption, SynDynOptionDescription]: ) -> Union[BaseOption, SynDynOptionDescription]:
"""get children """get children
""" """
# if path: for child in self._children[1]:
# subpath = path
if dynoption:
self_opt = dynoption
else:
self_opt = self
if not dyn or config_bag is undefined or \
config_bag.context.get_description() == self:
subpath = ''
else:
subpath = self_opt.impl_getpath()
for child in self._children[1]: # pylint: disable=no-member
if dyn and child.impl_is_dynoptiondescription(): if dyn and child.impl_is_dynoptiondescription():
for suffix in child.get_suffixes(config_bag, yield from self.get_suffixed_children(dynoption,
dynoption, [],
): config_bag,
yield child.to_dynoption(subpath,
suffix,
child,
)
elif dyn and child.issubdyn() or child.impl_is_dynsymlinkoption():
yield child.to_dynoption(subpath,
option_suffix,
child, child,
) )
else: else:
yield child yield child
def get_path(self,
config_bag,
dynoption,
):
if dynoption:
self_opt = dynoption
else:
self_opt = self
if config_bag is undefined or \
config_bag.context.get_description() == self:
return ''
return self_opt.impl_getpath()
def get_suffixed_children(self,
dynoption,
option_suffixes: list,
config_bag: ConfigBag,
child,
):
root_path = self.get_path(config_bag, dynoption)
for suffix in child.get_suffixes(config_bag,
dynoption=dynoption,
):
yield child.to_dynoption(root_path,
option_suffixes + [suffix],
)
def get_children_recursively(self, def get_children_recursively(self,
bytype: Optional[BaseOption], bytype: Optional[BaseOption],
byname: Optional[str], byname: Optional[str],
config_bag: ConfigBag, config_bag: ConfigBag,
self_opt: BaseOption=None, self_opt: BaseOption=None,
*,
option_suffixes: Optional[list]=None
) -> Iterator[Union[BaseOption, SynDynOptionDescription]]: ) -> Iterator[Union[BaseOption, SynDynOptionDescription]]:
"""get children recursively """get children recursively
""" """
@ -402,19 +394,19 @@ class OptionDescription(OptionDescriptionWalk):
def to_dynoption(self, def to_dynoption(self,
rootpath: str, rootpath: str,
suffix: str, suffixes: Optional[list],
ori_dyn) -> SynDynOptionDescription: #ori_dyn,
) -> Union[SubDynOptionDescription, SynDynOptionDescription]:
"""get syn dyn option description """get syn dyn option description
""" """
if suffix is None: if self.impl_is_dynoptiondescription():
return SubDynOptionDescription(self, obj = SynDynOptionDescription
else:
obj = SubDynOptionDescription
return obj(self,
rootpath, rootpath,
ori_dyn, suffixes,
) )
return SynDynOptionDescription(self,
rootpath,
suffix,
ori_dyn)
def impl_is_dynsymlinkoption(self) -> bool: def impl_is_dynsymlinkoption(self) -> bool:
"""option is not a dyn symlink option """option is not a dyn symlink option

View file

@ -47,11 +47,12 @@ class SymLinkOption(BaseOption):
_setattr(self, '_name', name) _setattr(self, '_name', name)
_setattr(self, '_opt', opt) _setattr(self, '_opt', opt)
opt._add_dependency(self) opt._add_dependency(self)
self._path = None
def __getattr__(self, def __getattr__(self,
name: str, name: str,
) -> Any: ) -> Any:
if name == '_path':
raise AttributeError()
return getattr(self._opt, name) return getattr(self._opt, name)
def _setsubdyn(self, def _setsubdyn(self,

View file

@ -29,20 +29,17 @@ class SynDynOption:
""" """
__slots__ = ('rootpath', __slots__ = ('rootpath',
'opt', 'opt',
'suffix', 'suffixes',
'dyn_parent',
'__weakref__') '__weakref__')
def __init__(self, def __init__(self,
opt: BaseOption, opt: BaseOption,
rootpath: str, rootpath: str,
suffix: str, suffixes: list,
dyn_parent,
) -> None: ) -> None:
self.opt = opt self.opt = opt
self.rootpath = rootpath self.rootpath = rootpath
self.suffix = suffix self.suffixes = suffixes
self.dyn_parent = dyn_parent
def __getattr__(self, def __getattr__(self,
name: str) -> Any: name: str) -> Any:
@ -60,10 +57,10 @@ class SynDynOption:
""" """
return self.opt.impl_get_display_name(self) return self.opt.impl_get_display_name(self)
def impl_getsuffix(self) -> str: def get_suffixes(self) -> str:
"""get suffix """get suffix
""" """
return self.suffix return self.suffixes
def impl_getpath(self) -> str: def impl_getpath(self) -> str:
"""get path """get path
@ -85,6 +82,5 @@ class SynDynOption:
if leadership: if leadership:
rootpath = self.rootpath.rsplit('.', 1)[0] rootpath = self.rootpath.rsplit('.', 1)[0]
return leadership.to_dynoption(rootpath, return leadership.to_dynoption(rootpath,
self.suffix, self.suffixes,
self.dyn_parent,
) )

View file

@ -30,155 +30,75 @@ from .baseoption import BaseOption
from .syndynoption import SynDynOption from .syndynoption import SynDynOption
class SubDynOptionDescription: class Syn:
__slots__ = ('rootpath', __slots__ = ('opt',
'opt', 'rootpath',
'dyn_parent', '_suffixes',
'__weakref__',
) )
def __init__(self, def __init__(self,
opt: BaseOption, opt: BaseOption,
rootpath: str, rootpath: str,
dyn_parent, suffixes: list,
) -> None: ) -> None:
self.opt = opt self.opt = opt
self.rootpath = rootpath self.rootpath = rootpath
self.dyn_parent = dyn_parent self._suffixes = suffixes
def impl_getpath(self) -> str:
"""get path
"""
path = self.opt.impl_getname()
if self.rootpath:
path = f'{self.rootpath}.{path}'
return path
def get_sub_children(self,
option,
config_bag,
*,
index=None,
properties=undefined,
):
return self.opt.get_sub_children(option,
config_bag,
index=index,
properties=properties,
dynoption=self,
)
def getsubdyn(self):
return self.opt.getsubdyn()
def impl_is_optiondescription(self):
return True
def impl_is_dynsymlinkoption(self):
return True
def impl_is_sub_dyn_optiondescription(self):
return True
def impl_get_display_name(self) -> str: def impl_get_display_name(self) -> str:
return self.opt.impl_get_display_name(self) return self.opt.impl_get_display_name(self)
def impl_is_dynoptiondescription(self) -> bool:
return True
def to_dynoption(self,
rootpath: str,
suffix: str,
ori_dyn,
):
return self.opt.to_dynoption(rootpath, suffix, ori_dyn)
class SynDynOptionDescription:
"""SynDynOptionDescription internal option, it's an instanciate synoptiondescription
"""
__slots__ = ('opt',
'rootpath',
'_suffix',
'ori_dyn')
def __init__(self,
opt: BaseOption,
rootpath: str,
suffix: str,
ori_dyn) -> None:
self.opt = opt
self.rootpath = rootpath
self._suffix = suffix
# For a Leadership inside a DynOptionDescription
self.ori_dyn = ori_dyn
def __getattr__(self,
name: str,
) -> Any:
# if not in SynDynOptionDescription, get value in self.opt
return getattr(self.opt,
name,
)
def impl_getname(self) -> str:
"""get name
"""
if self.opt.impl_is_dynoptiondescription():
return self.opt.impl_getname(self._suffix)
return self.opt.impl_getname()
def impl_get_display_name(self) -> str:
"""get display name
"""
return self.opt.impl_get_display_name(self)
def get_children(self,
config_bag: ConfigBag,
dyn: bool=True,
):
# pylint: disable=unused-argument
"""get children
"""
yield from self.opt.get_children(config_bag,
dynoption=self,
option_suffix=self._suffix,
)
def get_child(self, def get_child(self,
name: str, name: str,
config_bag: ConfigBag, config_bag: ConfigBag,
subpath: str, *,
allow_dynoption: bool=False, allow_dynoption: bool=False,
): ):
"""get children """get children
""" """
return self.opt.get_child(name, # if not dyn
config_bag, option = self.opt.get_child_not_dynamic(name,
subpath, allow_dynoption,
dynoption=self,
option_suffix=self._suffix,
allow_dynoption=allow_dynoption,
) )
if option:
def get_sub_children(self, if allow_dynoption and option.impl_is_dynoptiondescription():
option, return option
config_bag, return option.to_dynoption(self.impl_getpath(),
*, self._suffixes,
index=None, )
properties=undefined, for child in self.opt._children[1]: # pylint: disable=no-member
if not child.impl_is_dynoptiondescription():
continue
for suffix in child.get_suffixes(config_bag,
dynoption=self,
): ):
return self.opt.get_sub_children(option, if name != child.impl_getname(suffix):
config_bag, continue
index=index, return child.to_dynoption(self.impl_getpath(),
properties=properties, self._suffixes + [suffix],
dynoption=self,
) )
raise AttributeError(_(f'unknown option "{name}" '
f'in optiondescription "{self.impl_get_display_name()}"'
))
def impl_is_dynsymlinkoption(self) -> bool: def get_children(self,
"""it's a dynsymlinkoption config_bag: ConfigBag,
):
# pylint: disable=unused-argument
"""get children
""" """
return True for child in self.opt._children[1]:
if child.impl_is_dynoptiondescription():
for suffix in child.get_suffixes(config_bag,
dynoption=self,
):
yield child.to_dynoption(self.impl_getpath(),
self._suffixes + [suffix],
)
else:
yield child.to_dynoption(self.impl_getpath(),
self._suffixes,
)
def get_children_recursively(self, def get_children_recursively(self,
bytype: Optional[BaseOption], bytype: Optional[BaseOption],
@ -196,6 +116,64 @@ class SynDynOptionDescription:
): ):
yield option yield option
def get_suffixes(self) -> str:
"""get suffixes
"""
return self._suffixes
def impl_is_dynsymlinkoption(self) -> bool:
"""it's a dynsymlinkoption
"""
return True
class SubDynOptionDescription(Syn):
def impl_getpath(self) -> str:
"""get path
"""
path = self.opt.impl_getname()
if self.rootpath:
path = f'{self.rootpath}.{path}'
return path
def getsubdyn(self):
return self.opt.getsubdyn()
def impl_is_optiondescription(self):
return True
def impl_is_symlinkoption(self):
return False
def impl_is_leadership(self):
return False
def impl_is_dynoptiondescription(self) -> bool:
return True
def impl_getproperties(self):
return self.opt.impl_getproperties()
class SynDynOptionDescription(Syn):
"""SynDynOptionDescription internal option, it's an instanciate synoptiondescription
"""
def __getattr__(self,
name: str,
) -> Any:
# if not in SynDynOptionDescription, get value in self.opt
return getattr(self.opt,
name,
)
def impl_getname(self) -> str:
"""get name
"""
if self.opt.impl_is_dynoptiondescription():
return self.opt.impl_getname(self._suffixes[-1])
return self.opt.impl_getname()
def impl_getpath(self) -> str: def impl_getpath(self) -> str:
"""get path """get path
""" """
@ -204,10 +182,8 @@ class SynDynOptionDescription:
path = f'{self.rootpath}.{path}' path = f'{self.rootpath}.{path}'
return path return path
def impl_getsuffix(self) -> str: def getsubdyn(self):
"""get suffix return self.opt
"""
return self._suffix
class SynDynLeadership(SynDynOptionDescription): class SynDynLeadership(SynDynOptionDescription):
@ -217,8 +193,7 @@ class SynDynLeadership(SynDynOptionDescription):
"""get the leader """get the leader
""" """
return self.opt.get_leader().to_dynoption(self.impl_getpath(), return self.opt.get_leader().to_dynoption(self.impl_getpath(),
self._suffix, self._suffixes,
self.ori_dyn,
) )
def get_followers(self) -> Iterator[SynDynOption]: def get_followers(self) -> Iterator[SynDynOption]:
@ -227,24 +202,7 @@ class SynDynLeadership(SynDynOptionDescription):
subpath = self.impl_getpath() subpath = self.impl_getpath()
for follower in self.opt.get_followers(): for follower in self.opt.get_followers():
yield follower.to_dynoption(subpath, yield follower.to_dynoption(subpath,
self._suffix, self._suffixes,
self.ori_dyn,
)
def reset_cache(self,
path: str,
config_bag: 'ConfigBag',
resetted_opts: List[str],
) -> None:
"""reset cache
"""
leader = self.get_leader()
followers = self.get_followers()
self._reset_cache(path,
leader,
followers,
config_bag,
resetted_opts,
) )
def pop(self, def pop(self,
@ -271,7 +229,7 @@ class SynDynLeadership(SynDynOptionDescription):
dyn=self, dyn=self,
) )
def impl_getsuffix(self) -> str: def get_suffixes(self) -> str:
"""get suffix """get suffix
""" """
return self._suffix return self._suffixes

View file

@ -192,7 +192,7 @@ class OptionBag:
elif option: elif option:
self.path = option.impl_getpath() self.path = option.impl_getpath()
context = config_bag.context context = config_bag.context
if '.' not in self.path and option == context.get_description(): if self.path is None:
self.properties = None self.properties = None
elif properties is undefined: elif properties is undefined:
settings = context.get_settings() settings = context.get_settings()
@ -704,20 +704,18 @@ class Settings:
uncalculated=uncalculated, uncalculated=uncalculated,
transitive_raise=transitive_raise, transitive_raise=transitive_raise,
) )
return self._calc_raises_properties(option_bag.config_bag.properties, return self._calc_raises_properties(option_bag,
option_bag.config_bag.permissives,
option_properties, option_properties,
) )
def _calc_raises_properties(self, def _calc_raises_properties(self,
context_properties, option_bag,
context_permissives,
option_properties, option_properties,
): ):
raises_properties = context_properties - SPECIAL_PROPERTIES raises_properties = option_bag.config_bag.properties - SPECIAL_PROPERTIES
# remove global permissive properties # remove global permissive properties
if raises_properties and 'permissive' in raises_properties: if raises_properties and 'permissive' in raises_properties:
raises_properties -= context_permissives raises_properties -= option_bag.config_bag.permissives
properties = option_properties & raises_properties properties = option_properties & raises_properties
# at this point it should not remain any property for the option # at this point it should not remain any property for the option
return properties return properties
@ -743,8 +741,7 @@ class Settings:
transitive_raise=transitive_raise, transitive_raise=transitive_raise,
)) ))
calc_properties = [] calc_properties = []
for property_ in self._calc_raises_properties(option_bag.config_bag.properties, for property_ in self._calc_raises_properties(option_bag,
option_bag.config_bag.permissives,
set(help_properties.keys()), set(help_properties.keys()),
): ):
calc_properties.append(help_properties[property_]) calc_properties.append(help_properties[property_])

View file

@ -152,12 +152,7 @@ class Values:
""" """
has_calculation = False has_calculation = False
if isinstance(value, Calculation): if isinstance(value, Calculation):
try:
value = value.execute(option_bag) value = value.execute(option_bag)
except ConfigError as err:
msg = _(f'error when calculating "{option_bag.option.impl_get_display_name()}": '
f'{err} : {option_bag.path}')
raise ConfigError(msg) from err
has_calculation = True has_calculation = True
elif isinstance(value, list): elif isinstance(value, list):
# if value is a list, do subcalculation # if value is a list, do subcalculation
@ -354,6 +349,7 @@ class Values:
for coption in option.get_children_recursively(None, for coption in option.get_children_recursively(None,
None, None,
option_bag.config_bag, option_bag.config_bag,
option_suffixes=[],
): ):
if 'force_store_value' in coption.impl_getproperties(): if 'force_store_value' in coption.impl_getproperties():
force_store_options.append(coption) force_store_options.append(coption)