Compare commits

..

No commits in common. "c7d4dfb2a471c4c3735068dc9f87166396106c56" and "93fa26f8df48c3ea8e8c88dcb8ade7b2894b3759" have entirely different histories.

21 changed files with 408 additions and 931 deletions

View file

@ -1,6 +0,0 @@
[tool.commitizen]
name = "cz_conventional_commits"
tag_format = "$version"
version_scheme = "semver"
version = "4.0.2"
update_changelog_on_bump = true

View file

@ -1,12 +0,0 @@
## 4.0.2 (2024-02-20)
### Fix
- sub dynamic in sub dynamic family
## 4.0.1 (2023-12-17)
### Feat
- documentation
- dynamic family can have sub family

View file

@ -11,12 +11,13 @@ 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-10 :lines: 3-11
:linenos: :linenos:
Let's try our object: Let's try our object:
@ -30,30 +31,31 @@ Let's try our object:
... ...
"oooups" is an invalid string with vowel for "Vowel" "oooups" is an invalid string with vowel for "Vowel"
Create your own option Create you 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 a lipogram option: Here an example to an lipogram option:
.. literalinclude:: src/own_option2.py .. literalinclude:: src/own_option2.py
:lines: 3-12 :lines: 3-15
: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: 13-17 :lines: 16-20
: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: 19-26 :lines: 22-29
:linenos: :linenos:
Even if user set warnings_only attribute, this method will raise. Even if user set warnings_only attribute, this method will raise.
@ -61,7 +63,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: 28-40 :lines: 31-43
:linenos: :linenos:
Let's test it: Let's test it:

View file

@ -7,4 +7,5 @@ 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,11 +1,14 @@
#!/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(None) o._build_cache()
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(None) o._build_cache()
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() == 'doc1' assert cfg.option('od.dodval1.st').doc() == 'doc1val1'
assert cfg.option('od.dodval2.st').doc() == 'doc1' assert cfg.option('od.dodval2.st').doc() == 'doc1val2'
assert cfg.option('od.dodval1').doc() == 'doc2' assert cfg.option('od.dodval1').doc() == 'doc2val1'
assert cfg.option('od.dodval2').doc() == 'doc2' assert cfg.option('od.dodval2').doc() == 'doc2val2'
# assert not list_sessions() # assert not list_sessions()
@ -1792,6 +1792,7 @@ 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)
@ -2078,7 +2079,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)
assert cfg.value.mandatory() == [] cfg.value.mandatory()
# assert not list_sessions() # assert not list_sessions()
@ -2108,542 +2109,3 @@ 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,12 +458,13 @@ class TiramisuOptionProperty(CommonTiramisuOption):
): ):
"""Get properties for an option""" """Get properties for an option"""
option_bag = options_bag[-1] option_bag = options_bag[-1]
settings = self._config_bag.context.get_settings()
if not only_raises: if not only_raises:
return settings.getproperties(option_bag) return option_bag.properties
return settings.calc_raises_properties(option_bag, settings = self._config_bag.context.get_settings()
uncalculated=uncalculated, ret = settings.calc_raises_properties(option_bag,
) 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,
@ -490,11 +491,10 @@ 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]
settings = self._config_bag.context.get_settings() props = option_bag.properties
props = settings.getproperties(option_bag) self._config_bag.context.get_settings().setproperties(option_bag,
settings.setproperties(option_bag, props - {prop},
props - {prop}, )
)
@option_type(['option', 'optiondescription', 'with_or_without_index']) @option_type(['option', 'optiondescription', 'with_or_without_index'])
def reset(self, options_bag: List[OptionBag]): def reset(self, options_bag: List[OptionBag]):

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
display_name = option_bag.option.impl_get_display_name() raise ConfigError(_('unable to carry out a calculation for "{}"'
raise ConfigError(_('unable to carry out a calculation for "{}", {}').format(display_name, err)) from err ', {}').format(option.impl_get_display_name(), err), err) from err
except ValueError as err: except ValueError as err:
raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(option_bag.option.impl_get_display_name(), err)) from err raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(option_bag.option.impl_get_display_name(), err)) from err
except AttributeError as err: except AttributeError as err:
@ -324,8 +324,7 @@ def manager_callback(callback: Callable,
['configerror'], ['configerror'],
config_bag.context.get_settings(), config_bag.context.get_settings(),
) )
display_name = option_bag.option.impl_get_display_name() raise ConfigError(_(f'unable to get value for calculating "{option_bag.option.impl_get_display_name()}", {err}')) from err
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,
@ -360,8 +359,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
display_name = option.impl_get_display_name() raise ConfigError(_('unable to carry out a calculation for "{}"'
raise ConfigError(_('unable to carry out a calculation for "{}", {}').format(display_name, err)) from err ', {}').format(option.impl_get_display_name(), err), err) from err
except ValueError as err: except ValueError as err:
raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(option.impl_get_display_name(), err)) from err raise ValueError(_('the option "{0}" is used in a calculation but is invalid ({1})').format(option.impl_get_display_name(), err)) from err
except AttributeError as err: except AttributeError as err:
@ -371,8 +370,7 @@ def manager_callback(callback: Callable,
['configerror'], ['configerror'],
config_bag.context.get_settings(), config_bag.context.get_settings(),
) )
display_name = option.impl_get_display_name() raise ConfigError(_(f'unable to get value for calculating "{option.impl_get_display_name()}", {err}')) from err
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:
@ -401,17 +399,17 @@ def manager_callback(callback: Callable,
param.default_value, param.default_value,
) )
except ValueError as err: except ValueError as err:
display_name = option.impl_get_display_name() raise ConfigError(_('option "{}" cannot be calculated: {}').format(option.impl_get_display_name(),
raise ConfigError(_(f'unable to get value for calculating "{display_name}", {err}')) from err str(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():
display_name = option_bag.option.impl_get_display_name() raise ConfigError(_('option "{}" is not in a dynoptiondescription').format(option.impl_get_display_name()))
raise ConfigError(_('option "{display_name}" is not in a dynoptiondescription')) return option.impl_getsuffix()
return option.get_suffixes()[-1]
if isinstance(param, ParamSelfOption): if isinstance(param, ParamSelfOption):
value = calc_self(param, value = calc_self(param,
@ -454,26 +452,46 @@ 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()
in_same_dyn = False if option.opt.issubdyn() and callbk_option.getsubdyn() == option.getsubdyn() or \
if not option.opt.issubdyn() and callbk_option.getsubdyn() == option.opt: not option.opt.issubdyn() and callbk_option.getsubdyn() == option.opt:
# First dyn # in same dynoption
in_same_dyn = True suffix = option.impl_getsuffix()
elif option.opt.issubdyn(): subdyn = callbk_option.getsubdyn()
# Search if callback and option has a common subdyn root_path, sub_path = subdyn.split_path(subdyn,
callbk_subdyn = callbk_option.getsubdyn() option,
sub_dyn = option )
while True: if root_path:
sub_dyn = sub_dyn.getsubdyn() parent_path = root_path + subdyn.impl_getname(suffix) + sub_path
if sub_dyn == callbk_subdyn: else:
in_same_dyn = True parent_path = subdyn.impl_getname(suffix) + sub_path
break callbk_option = callbk_option.to_dynoption(parent_path,
if not sub_dyn.issubdyn(): suffix,
break subdyn,
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 = []
@ -501,6 +519,8 @@ 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,
@ -582,7 +602,6 @@ 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,6 +27,7 @@ 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 _
@ -163,19 +164,9 @@ 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(): self._reset_cache_dyn_optiondescription(options_bag[-1],
for suffix in options_bag[-1].option.get_suffixes(config_bag, dynoption=options_bag[-2].option): resetted_opts,
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],
resetted_opts,
)
break break
else: else:
soption_bag = OptionBag(option, soption_bag = OptionBag(option,
@ -191,38 +182,19 @@ 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]
dynopt = option.get_sub_dyns()[-1]() for wdynopt in reversed(option.get_sub_dyns()):
dyn_path = dynopt.impl_getpath() dynopt = wdynopt()
if '.' in dyn_path: sub_options = []
root_path = dyn_path.rsplit('.', 1)[0] for sub_option in options:
else: sub_options.extend(dynopt.get_sub_children(sub_option.option,
root_path = '' config_bag,
for suffix in dynopt.get_suffixes(config_bag): properties=None,
suffix_dynopt = dynopt.to_dynoption(root_path, ))
[suffix], options = sub_options
) for doption_bag in options:
soption_bag = OptionBag(suffix_dynopt, None, config_bag) self.reset_one_option_cache(resetted_opts,
for data in self.walk(soption_bag, validate_properties=False): doption_bag,
if isinstance(data, dict): )
leader = data.pop('leader')
resetted_opts.append(leader.path)
leader.option.reset_cache(leader.path,
config_bag,
resetted_opts,
)
for followers in data.values():
for follower in followers:
resetted_opts.append(follower.path)
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,
soption_bag, soption_bag,
@ -263,11 +235,16 @@ class _SubConfig:
option_bag, option_bag,
resetted_opts, resetted_opts,
): ):
for doption_bag in option_bag.option.get_sub_children(option_bag.option, option = option_bag.option
option_bag.config_bag, if isinstance(option, (DynOptionDescription, SubDynOptionDescription)):
index=option_bag.index, dynoption = option
properties=None else:
): dynoption = option.getsubdyn()
for doption_bag in dynoption.get_sub_children(option,
option_bag.config_bag,
index=option_bag.index,
properties=None
):
self.reset_one_option_cache(resetted_opts, self.reset_one_option_cache(resetted_opts,
doption_bag, doption_bag,
) )
@ -361,13 +338,11 @@ 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
""" """
@ -387,14 +362,13 @@ 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,
validate_properties, True,
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']):
@ -406,7 +380,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,
validate_properties, True,
)[-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,
@ -429,7 +403,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,
validate_properties, True,
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],
@ -437,7 +411,6 @@ 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
@ -603,7 +576,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(self._display_name) # pylint: disable=no-member,protected-access descr._build_cache(display_name=self._display_name) # pylint: disable=no-member,protected-access
if not hasattr(descr, '_cache_force_store_values'): if not hasattr(descr, '_cache_force_store_values'):
raise ConfigError(_('option description seems to be part of an other ' raise ConfigError(_('option description seems to be part of an other '
'config')) 'config'))
@ -754,8 +727,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,
@ -782,8 +755,13 @@ 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:
@ -809,9 +787,6 @@ 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,7 +166,8 @@ class Base:
def impl_is_readonly(self) -> str: def impl_is_readonly(self) -> str:
"""the option is readonly """the option is readonly
""" """
return hasattr(self, '_path') # _path is None when initialise SymLinkOption
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
@ -321,34 +322,3 @@ 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,7 +88,6 @@ 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
@ -135,9 +134,8 @@ 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
@ -171,8 +169,8 @@ class DynOptionDescription(OptionDescription):
properties=undefined, properties=undefined,
dynoption=None, dynoption=None,
): ):
root_path, sub_path = self.split_path(option, root_path, sub_path = self.split_path(dynoption,
dynoption=dynoption, option,
) )
for suffix in self.get_suffixes(config_bag, for suffix in self.get_suffixes(config_bag,
dynoption=dynoption, dynoption=dynoption,
@ -184,7 +182,8 @@ 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,9 +248,11 @@ class Leadership(OptionDescription):
def to_dynoption(self, def to_dynoption(self,
rootpath: str, rootpath: str,
suffixes: Optional[list], suffix: str,
ori_dyn,
) -> SynDynLeadership: ) -> SynDynLeadership:
return SynDynLeadership(self, return SynDynLeadership(self,
rootpath, rootpath,
suffixes, suffix,
ori_dyn,
) )

View file

@ -464,13 +464,15 @@ class Option(BaseOption):
def to_dynoption(self, def to_dynoption(self,
rootpath: str, rootpath: str,
suffixes: list[str], suffix: 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,
suffixes, suffix,
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(display_name, option._build_cache(_consistencies,
_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,6 +96,15 @@ 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:
@ -105,7 +114,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 = None # pylint: disable=attribute-defined-outside-init,no-member self._path = self._name # pylint: disable=attribute-defined-outside-init,no-member
self._set_readonly() self._set_readonly()
def impl_build_force_store_values(self, def impl_build_force_store_values(self,
@ -137,8 +146,10 @@ 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():
doption = option.to_dynoption(leader_option_bag.option.rootpath, subpath = leader_option_bag.option.rootpath
leader_option_bag.option.get_suffixes(), doption = option.to_dynoption(subpath,
leader_option_bag.option.impl_getsuffix(),
leader_option_bag.option.dyn_parent,
) )
else: else:
doption = option doption = option
@ -179,48 +190,56 @@ 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
option = self.get_child_not_dynamic(name, if name in self._children[0]: # pylint: disable=no-member
allow_dynoption, option = self._children[1][self._children[0].index(name)] # pylint: disable=no-member
) if option.impl_is_dynoptiondescription():
if option: 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,
)
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(self.impl_getpath(), return child.to_dynoption(subpath,
[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.impl_get_display_name()}"' f'in optiondescription "{self_opt.impl_get_display_name()}"'
)) ))
def get_children(self, def get_children(self,
@ -229,54 +248,43 @@ 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
""" """
for child in self._children[1]: # if path:
if dyn and child.impl_is_dynoptiondescription(): # subpath = path
yield from self.get_suffixed_children(dynoption,
[],
config_bag,
child,
)
else:
yield child
def get_path(self,
config_bag,
dynoption,
):
if dynoption: if dynoption:
self_opt = dynoption self_opt = dynoption
else: else:
self_opt = self self_opt = self
if config_bag is undefined or \ if not dyn or config_bag is undefined or \
config_bag.context.get_description() == self: config_bag.context.get_description() == self:
return '' subpath = ''
return self_opt.impl_getpath() else:
subpath = self_opt.impl_getpath()
def get_suffixed_children(self, for child in self._children[1]: # pylint: disable=no-member
dynoption, if dyn and child.impl_is_dynoptiondescription():
option_suffixes: list, for suffix in child.get_suffixes(config_bag,
config_bag: ConfigBag, dynoption,
child, ):
): yield child.to_dynoption(subpath,
root_path = self.get_path(config_bag, dynoption) suffix,
for suffix in child.get_suffixes(config_bag, child,
dynoption=dynoption, )
): elif dyn and child.issubdyn() or child.impl_is_dynsymlinkoption():
yield child.to_dynoption(root_path, yield child.to_dynoption(subpath,
option_suffixes + [suffix], option_suffix,
) child,
)
else:
yield child
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
""" """
@ -394,19 +402,19 @@ class OptionDescription(OptionDescriptionWalk):
def to_dynoption(self, def to_dynoption(self,
rootpath: str, rootpath: str,
suffixes: Optional[list], suffix: str,
#ori_dyn, ori_dyn) -> SynDynOptionDescription:
) -> Union[SubDynOptionDescription, SynDynOptionDescription]:
"""get syn dyn option description """get syn dyn option description
""" """
if self.impl_is_dynoptiondescription(): if suffix is None:
obj = SynDynOptionDescription return SubDynOptionDescription(self,
else: rootpath,
obj = SubDynOptionDescription ori_dyn,
return obj(self, )
rootpath, return SynDynOptionDescription(self,
suffixes, 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,12 +47,11 @@ 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,17 +29,20 @@ class SynDynOption:
""" """
__slots__ = ('rootpath', __slots__ = ('rootpath',
'opt', 'opt',
'suffixes', 'suffix',
'dyn_parent',
'__weakref__') '__weakref__')
def __init__(self, def __init__(self,
opt: BaseOption, opt: BaseOption,
rootpath: str, rootpath: str,
suffixes: list, suffix: str,
dyn_parent,
) -> None: ) -> None:
self.opt = opt self.opt = opt
self.rootpath = rootpath self.rootpath = rootpath
self.suffixes = suffixes self.suffix = suffix
self.dyn_parent = dyn_parent
def __getattr__(self, def __getattr__(self,
name: str) -> Any: name: str) -> Any:
@ -57,10 +60,10 @@ class SynDynOption:
""" """
return self.opt.impl_get_display_name(self) return self.opt.impl_get_display_name(self)
def get_suffixes(self) -> str: def impl_getsuffix(self) -> str:
"""get suffix """get suffix
""" """
return self.suffixes return self.suffix
def impl_getpath(self) -> str: def impl_getpath(self) -> str:
"""get path """get path
@ -82,5 +85,6 @@ 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.suffixes, self.suffix,
self.dyn_parent,
) )

View file

@ -30,76 +30,156 @@ from .baseoption import BaseOption
from .syndynoption import SynDynOption from .syndynoption import SynDynOption
class Syn: class SubDynOptionDescription:
__slots__ = ('opt', __slots__ = ('rootpath',
'rootpath', 'opt',
'_suffixes', 'dyn_parent',
'__weakref__',
) )
def __init__(self, def __init__(self,
opt: BaseOption, opt: BaseOption,
rootpath: str, rootpath: str,
suffixes: list, dyn_parent,
) -> None: ) -> None:
self.opt = opt self.opt = opt
self.rootpath = rootpath self.rootpath = rootpath
self._suffixes = suffixes self.dyn_parent = dyn_parent
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 get_child(self, def impl_is_dynoptiondescription(self) -> bool:
name: str, return True
config_bag: ConfigBag,
*, def to_dynoption(self,
allow_dynoption: bool=False, rootpath: str,
): suffix: str,
"""get children 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 not dyn if self.opt.impl_is_dynoptiondescription():
option = self.opt.get_child_not_dynamic(name, return self.opt.impl_getname(self._suffix)
allow_dynoption, return self.opt.impl_getname()
)
if option: def impl_get_display_name(self) -> str:
if allow_dynoption and option.impl_is_dynoptiondescription(): """get display name
return option """
return option.to_dynoption(self.impl_getpath(), return self.opt.impl_get_display_name(self)
self._suffixes,
)
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,
):
if name != child.impl_getname(suffix):
continue
return child.to_dynoption(self.impl_getpath(),
self._suffixes + [suffix],
)
raise AttributeError(_(f'unknown option "{name}" '
f'in optiondescription "{self.impl_get_display_name()}"'
))
def get_children(self, def get_children(self,
config_bag: ConfigBag, config_bag: ConfigBag,
dyn: bool=True,
): ):
# pylint: disable=unused-argument # pylint: disable=unused-argument
"""get children """get children
""" """
for child in self.opt._children[1]: yield from self.opt.get_children(config_bag,
if child.impl_is_dynoptiondescription(): dynoption=self,
for suffix in child.get_suffixes(config_bag, option_suffix=self._suffix,
dynoption=self,
):
yield child.to_dynoption(self.impl_getpath(),
self._suffixes + [suffix],
)
else:
yield child.to_dynoption(self.impl_getpath(),
self._suffixes,
) )
def get_child(self,
name: str,
config_bag: ConfigBag,
subpath: str,
allow_dynoption: bool=False,
):
"""get children
"""
return self.opt.get_child(name,
config_bag,
subpath,
dynoption=self,
option_suffix=self._suffix,
allow_dynoption=allow_dynoption,
)
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 impl_is_dynsymlinkoption(self) -> bool:
"""it's a dynsymlinkoption
"""
return True
def get_children_recursively(self, def get_children_recursively(self,
bytype: Optional[BaseOption], bytype: Optional[BaseOption],
byname: Optional[str], byname: Optional[str],
@ -116,64 +196,6 @@ class Syn:
): ):
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
""" """
@ -182,8 +204,10 @@ class SynDynOptionDescription(Syn):
path = f'{self.rootpath}.{path}' path = f'{self.rootpath}.{path}'
return path return path
def getsubdyn(self): def impl_getsuffix(self) -> str:
return self.opt """get suffix
"""
return self._suffix
class SynDynLeadership(SynDynOptionDescription): class SynDynLeadership(SynDynOptionDescription):
@ -193,7 +217,8 @@ 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._suffixes, self._suffix,
self.ori_dyn,
) )
def get_followers(self) -> Iterator[SynDynOption]: def get_followers(self) -> Iterator[SynDynOption]:
@ -202,9 +227,26 @@ 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._suffixes, self._suffix,
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,
*args, *args,
**kwargs, **kwargs,
@ -229,7 +271,7 @@ class SynDynLeadership(SynDynOptionDescription):
dyn=self, dyn=self,
) )
def get_suffixes(self) -> str: def impl_getsuffix(self) -> str:
"""get suffix """get suffix
""" """
return self._suffixes return self._suffix

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 self.path is None: if '.' not in self.path and option == context.get_description():
self.properties = None self.properties = None
elif properties is undefined: elif properties is undefined:
settings = context.get_settings() settings = context.get_settings()
@ -704,18 +704,20 @@ class Settings:
uncalculated=uncalculated, uncalculated=uncalculated,
transitive_raise=transitive_raise, transitive_raise=transitive_raise,
) )
return self._calc_raises_properties(option_bag, return self._calc_raises_properties(option_bag.config_bag.properties,
option_bag.config_bag.permissives,
option_properties, option_properties,
) )
def _calc_raises_properties(self, def _calc_raises_properties(self,
option_bag, context_properties,
context_permissives,
option_properties, option_properties,
): ):
raises_properties = option_bag.config_bag.properties - SPECIAL_PROPERTIES raises_properties = context_properties - SPECIAL_PROPERTIES
# remove global permissive properties # remove global permissive properties
if raises_properties and 'permissive' in raises_properties: if raises_properties and 'permissive' in raises_properties:
raises_properties -= option_bag.config_bag.permissives raises_properties -= context_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
@ -741,7 +743,8 @@ class Settings:
transitive_raise=transitive_raise, transitive_raise=transitive_raise,
)) ))
calc_properties = [] calc_properties = []
for property_ in self._calc_raises_properties(option_bag, for property_ in self._calc_raises_properties(option_bag.config_bag.properties,
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,7 +152,12 @@ class Values:
""" """
has_calculation = False has_calculation = False
if isinstance(value, Calculation): if isinstance(value, Calculation):
value = value.execute(option_bag) try:
value = value.execute(option_bag)
except ConfigError as err:
msg = _(f'error when calculating "{option_bag.option.impl_get_display_name()}": '
f'{err} : {option_bag.path}')
raise ConfigError(msg) from err
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
@ -349,7 +354,6 @@ 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)