feat: better identifiers retrieve
This commit is contained in:
parent
f3a7344b58
commit
24b0ce9443
6 changed files with 157 additions and 56 deletions
|
|
@ -508,8 +508,8 @@ def test_dyndescription_subdyn():
|
||||||
assert set(cfg.option('od.dod2val1.dodval1.st').property.get()) == {'validator'}
|
assert set(cfg.option('od.dod2val1.dodval1.st').property.get()) == {'validator'}
|
||||||
assert set(cfg.option('od.dod2val1.dodval1.st').property.get(uncalculated=True)) == {'validator'}
|
assert set(cfg.option('od.dod2val1.dodval1.st').property.get(uncalculated=True)) == {'validator'}
|
||||||
assert set(cfg.option('od.dod2.dod.st').property.get(uncalculated=True)) == {'validator'}
|
assert set(cfg.option('od.dod2.dod.st').property.get(uncalculated=True)) == {'validator'}
|
||||||
with pytest.raises(AttributeOptionError):
|
# with pytest.raises(AttributeOptionError):
|
||||||
cfg.option('od.dod2.dodval1.st').property.get(uncalculated=True)
|
assert set(cfg.option('od.dod2.dodval1.st').property.get(uncalculated=True)) == {'validator'}
|
||||||
assert cfg.option('od.dod2val1.dod.st').property.get(uncalculated=True) == {'validator'}
|
assert cfg.option('od.dod2val1.dod.st').property.get(uncalculated=True) == {'validator'}
|
||||||
#
|
#
|
||||||
with pytest.raises(AttributeOptionError):
|
with pytest.raises(AttributeOptionError):
|
||||||
|
|
@ -540,11 +540,13 @@ def test_dyndescription_subdyn():
|
||||||
assert cfg.option('od.dod2.dod').group_type() == "default"
|
assert cfg.option('od.dod2.dod').group_type() == "default"
|
||||||
assert cfg.option('od.dod2val1.dodval1').group_type() == "default"
|
assert cfg.option('od.dod2val1.dodval1').group_type() == "default"
|
||||||
#
|
#
|
||||||
with pytest.raises(AttributeOptionError):
|
assert cfg.option('od.dod2.dod').identifiers() == [['val1', 'val1'], ['val1', 'val2'], ['val2', 'val1'], ['val2', 'val2']]
|
||||||
cfg.option('od.dod2.dod').identifiers()
|
|
||||||
assert cfg.option('od.dod2.dod').identifiers(only_self=True) == ['val1', 'val2']
|
assert cfg.option('od.dod2.dod').identifiers(only_self=True) == ['val1', 'val2']
|
||||||
assert cfg.option('od.dod2val1.dodval1').identifiers() == ['val1', 'val1']
|
assert cfg.option('od.dod2val1.dodval1').identifiers() == ['val1', 'val1']
|
||||||
assert cfg.option('od.dod2val1.dodval1').identifiers(only_self=True) == ['val1', 'val2']
|
assert cfg.option('od.dod2val1.dodval1').identifiers(only_self=True) == ['val1', 'val2']
|
||||||
|
assert cfg.option('od.dod2val1.dodval2').identifiers() == ['val1', 'val2']
|
||||||
|
assert cfg.option('od.dod2val1.dod').identifiers() == [['val1', 'val1'], ['val1', 'val2']]
|
||||||
|
assert cfg.option('od.dod2.dodval1.st').identifiers() == [['val1', 'val1'], ['val2', 'val1']]
|
||||||
|
|
||||||
|
|
||||||
def test_callback_dyndescription_subdyn():
|
def test_callback_dyndescription_subdyn():
|
||||||
|
|
@ -562,6 +564,37 @@ def test_callback_dyndescription_subdyn():
|
||||||
assert parse_od_get(cfg.value.get()) == {'od.dod2val1.dodval1.st': 'val1', 'od.dod2val1.dodval3.st': 'val1', 'od.dod2val1.out': ['val1', 'val1'], 'od.dod2val3.dodval1.st': 'val1', 'od.dod2val3.dodval3.st': 'val1', 'od.dod2val3.out': ['val1', 'val1'], 'lst': ['val1', 'val3']}
|
assert parse_od_get(cfg.value.get()) == {'od.dod2val1.dodval1.st': 'val1', 'od.dod2val1.dodval3.st': 'val1', 'od.dod2val1.out': ['val1', 'val1'], 'od.dod2val3.dodval1.st': 'val1', 'od.dod2val3.dodval3.st': 'val1', 'od.dod2val3.out': ['val1', 'val1'], 'lst': ['val1', 'val3']}
|
||||||
cfg.option('lst').value.set(["val1", "val3", None])
|
cfg.option('lst').value.set(["val1", "val3", None])
|
||||||
assert parse_od_get(cfg.value.get()) == {'od.dod2val1.dodval1.st': 'val1', 'od.dod2val1.dodval3.st': 'val1', 'od.dod2val1.out': ['val1', 'val1'], 'od.dod2val3.dodval1.st': 'val1', 'od.dod2val3.dodval3.st': 'val1', 'od.dod2val3.out': ['val1', 'val1'], 'lst': ['val1', 'val3', None]}
|
assert parse_od_get(cfg.value.get()) == {'od.dod2val1.dodval1.st': 'val1', 'od.dod2val1.dodval3.st': 'val1', 'od.dod2val1.out': ['val1', 'val1'], 'od.dod2val3.dodval1.st': 'val1', 'od.dod2val3.dodval3.st': 'val1', 'od.dod2val3.out': ['val1', 'val1'], 'lst': ['val1', 'val3', None]}
|
||||||
|
assert cfg.option('od.dod2.dod.st').identifiers() == [['val1', 'val1'], ['val1', 'val3'], ['val3', 'val1'], ['val3', 'val3']]
|
||||||
|
assert cfg.option('od.dod2.dod').identifiers(only_self=True) == ['val1', 'val3']
|
||||||
|
assert cfg.option('od.dod2val1.dod.st').identifiers() == [['val1', 'val1'], ['val1', 'val3']]
|
||||||
|
assert cfg.option('od.dod2val1.dodval1.st').identifiers() == ['val1', 'val1']
|
||||||
|
assert cfg.option('od.dod2val1.dodval1').identifiers(only_self=True) == ['val1', 'val3']
|
||||||
|
|
||||||
|
|
||||||
|
def test_callback_dyndescription_subdyn2():
|
||||||
|
lst1 = StrOption('lst1', '', ['val1', 'val2'], multi=True)
|
||||||
|
lst2 = StrOption('lst2', '', ['val3', 'val4'], multi=True)
|
||||||
|
st = StrOption('st', '', 'val1')
|
||||||
|
dod = DynOptionDescription('dod', '', [st], identifiers=Calculation(return_list, Params(ParamOption(lst1))))
|
||||||
|
out = StrOption('out', '', Calculation(return_dynval, Params(ParamDynOption(st, [None, 'val1']))), multi=True, properties=('notunique',))
|
||||||
|
dod2 = DynOptionDescription('dod2', '', [dod, out], identifiers=Calculation(return_list, Params(ParamOption(lst2))))
|
||||||
|
od = OptionDescription('od', '', [dod2])
|
||||||
|
od2 = OptionDescription('od', '', [od, lst1, lst2])
|
||||||
|
cfg = Config(od2)
|
||||||
|
cfg.property.read_write()
|
||||||
|
#
|
||||||
|
assert parse_od_get(cfg.value.get()) == {'od.dod2val3.dodval1.st': 'val1', 'od.dod2val3.dodval2.st': 'val1', 'od.dod2val3.out': ['val1', 'val1'], 'od.dod2val4.dodval1.st': 'val1', 'od.dod2val4.dodval2.st': 'val1', 'od.dod2val4.out': ['val1', 'val1'], 'lst1': ['val1', 'val2'], 'lst2': ['val3', 'val4']}
|
||||||
|
#
|
||||||
|
cfg.option('lst1').value.set(["val1", "val3"])
|
||||||
|
assert parse_od_get(cfg.value.get()) == {'od.dod2val3.dodval1.st': 'val1', 'od.dod2val3.dodval3.st': 'val1', 'od.dod2val3.out': ['val1', 'val1'], 'od.dod2val4.dodval1.st': 'val1', 'od.dod2val4.dodval3.st': 'val1', 'od.dod2val4.out': ['val1', 'val1'], 'lst1': ['val1', 'val3'], 'lst2': ['val3', 'val4']}
|
||||||
|
#
|
||||||
|
cfg.option('lst1').value.set(["val1", "val3", None])
|
||||||
|
assert parse_od_get(cfg.value.get()) == {'od.dod2val3.dodval1.st': 'val1', 'od.dod2val3.dodval3.st': 'val1', 'od.dod2val3.out': ['val1', 'val1'], 'od.dod2val4.dodval1.st': 'val1', 'od.dod2val4.dodval3.st': 'val1', 'od.dod2val4.out': ['val1', 'val1'], 'lst1': ['val1', 'val3', None], 'lst2': ['val3', 'val4']}
|
||||||
|
assert cfg.option('od.dod2.dod.st').identifiers() == [['val3', 'val1'], ['val3', 'val3'], ['val4', 'val1'], ['val4', 'val3']]
|
||||||
|
assert cfg.option('od.dod2.dod').identifiers(only_self=True) == ['val1', 'val3']
|
||||||
|
assert cfg.option('od.dod2val3.dod.st').identifiers() == [['val3', 'val1'], ['val3', 'val3']]
|
||||||
|
assert cfg.option('od.dod2val3.dodval1.st').identifiers() == ['val3', 'val1']
|
||||||
|
assert cfg.option('od.dod2val3.dodval1').identifiers(only_self=True) == ['val1', 'val3']
|
||||||
|
|
||||||
|
|
||||||
def test_callback_list_dyndescription():
|
def test_callback_list_dyndescription():
|
||||||
|
|
@ -2220,6 +2253,8 @@ def test_leadership_dyndescription_convert():
|
||||||
assert cfg.option('od.stval2.st1.st1').owner.isdefault()
|
assert cfg.option('od.stval2.st1.st1').owner.isdefault()
|
||||||
assert cfg.option('od.stval2.st1.st1').identifiers() == ["val.2"]
|
assert cfg.option('od.stval2.st1.st1').identifiers() == ["val.2"]
|
||||||
assert cfg.option('od.stval2.st1.st1').identifiers(convert=True) == ["val2"]
|
assert cfg.option('od.stval2.st1.st1').identifiers(convert=True) == ["val2"]
|
||||||
|
assert cfg.option('od.st.st1.st1').identifiers() == [["val.1"], ["val.2"]]
|
||||||
|
assert cfg.option('od.st.st1.st1').identifiers(convert=True) == [["val1"], ["val2"]]
|
||||||
assert cfg.option('od.stval2').identifiers(only_self=True) == ["val.1", "val.2"]
|
assert cfg.option('od.stval2').identifiers(only_self=True) == ["val.1", "val.2"]
|
||||||
assert cfg.option('od.stval2').identifiers(only_self=True, convert=True) == ["val1", "val2"]
|
assert cfg.option('od.stval2').identifiers(only_self=True, convert=True) == ["val1", "val2"]
|
||||||
#
|
#
|
||||||
|
|
|
||||||
|
|
@ -1186,7 +1186,6 @@ def test_leadership_requires_leadership(config_type):
|
||||||
#
|
#
|
||||||
cfg.option('activate').value.set(False)
|
cfg.option('activate').value.set(False)
|
||||||
if config_type != 'tiramisu-api':
|
if config_type != 'tiramisu-api':
|
||||||
# FIXME
|
|
||||||
with pytest.raises(PropertiesOptionError):
|
with pytest.raises(PropertiesOptionError):
|
||||||
cfg.option('ip_admin_eth0.ip_admin_eth0').value.get()
|
cfg.option('ip_admin_eth0.ip_admin_eth0').value.get()
|
||||||
with pytest.raises(PropertiesOptionError):
|
with pytest.raises(PropertiesOptionError):
|
||||||
|
|
|
||||||
114
tiramisu/api.py
114
tiramisu/api.py
|
|
@ -135,11 +135,13 @@ class CommonTiramisu(TiramisuHelp):
|
||||||
config_bag=self._config_bag,
|
config_bag=self._config_bag,
|
||||||
parent=subconfig.parent,
|
parent=subconfig.parent,
|
||||||
identifiers=subconfig.identifiers,
|
identifiers=subconfig.identifiers,
|
||||||
|
identifier=None,
|
||||||
true_path=subconfig.true_path,
|
true_path=subconfig.true_path,
|
||||||
properties=subconfig.properties,
|
properties=subconfig.properties,
|
||||||
validate_properties=False,
|
validate_properties=False,
|
||||||
check_dynamic_without_identifiers=False,
|
check_dynamic_without_identifiers=False,
|
||||||
)
|
)
|
||||||
|
self._subconfig.is_self_dynamic_without_identifiers = subconfig.is_self_dynamic_without_identifiers
|
||||||
else:
|
else:
|
||||||
self._subconfig._length = None
|
self._subconfig._length = None
|
||||||
if not self._subconfig:
|
if not self._subconfig:
|
||||||
|
|
@ -148,18 +150,14 @@ class CommonTiramisu(TiramisuHelp):
|
||||||
self._config_bag,
|
self._config_bag,
|
||||||
self._path,
|
self._path,
|
||||||
self._index,
|
self._index,
|
||||||
validate_properties=False,
|
validate_properties=self._validate_properties,
|
||||||
allow_dynoption=True,
|
allow_dynoption=True,
|
||||||
)
|
)
|
||||||
except AssertionError as err:
|
except AssertionError as err:
|
||||||
raise ConfigError(str(err))
|
raise ConfigError(str(err))
|
||||||
|
|
||||||
|
|
||||||
def option_type(typ):
|
def option_type(types):
|
||||||
if not isinstance(typ, list):
|
|
||||||
types = [typ]
|
|
||||||
else:
|
|
||||||
types = typ
|
|
||||||
|
|
||||||
def wrapper(func):
|
def wrapper(func):
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
|
|
@ -179,7 +177,7 @@ def option_type(typ):
|
||||||
return func(self, options_bag, *args[1:], **kwargs)
|
return func(self, options_bag, *args[1:], **kwargs)
|
||||||
self._set_subconfig()
|
self._set_subconfig()
|
||||||
if (
|
if (
|
||||||
not isinstance(typ, list) or "allow_dynoption" not in typ
|
"allow_dynoption" not in types and not ("dynoption_or_uncalculated" in types and kwargs.get("uncalculated", False) is True)
|
||||||
) and self._subconfig.is_dynamic_without_identifiers:
|
) and self._subconfig.is_dynamic_without_identifiers:
|
||||||
raise AttributeOptionError(self._subconfig.path, "option-dynamic")
|
raise AttributeOptionError(self._subconfig.path, "option-dynamic")
|
||||||
|
|
||||||
|
|
@ -595,43 +593,88 @@ class _TiramisuOptionOptionDescription:
|
||||||
)
|
)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
def has_identifiers(self):
|
||||||
|
return self._subconfig.is_dynamic_without_identifiers
|
||||||
|
|
||||||
@option_type(["dynamic", "with_or_without_index", "allow_dynoption"])
|
@option_type(["dynamic", "with_or_without_index", "allow_dynoption"])
|
||||||
def identifiers(
|
def identifiers(
|
||||||
self,
|
self,
|
||||||
|
*,
|
||||||
only_self: bool = False,
|
only_self: bool = False,
|
||||||
uncalculated: bool = False,
|
uncalculated: bool = False,
|
||||||
convert: bool = False,
|
convert: bool = False,
|
||||||
):
|
):
|
||||||
"""Get identifiers for dynamic option"""
|
"""Get identifiers for dynamic option"""
|
||||||
subconfig = self._subconfig
|
subconfig = self._subconfig
|
||||||
if not only_self:
|
if only_self:
|
||||||
if self._subconfig.is_dynamic_without_identifiers and not uncalculated:
|
func = self._identifiers_only_self
|
||||||
raise AttributeOptionError(self._subconfig.path, "option-dynamic")
|
elif not subconfig.is_dynamic_without_identifiers:
|
||||||
if not convert:
|
func = self._identifiers_all
|
||||||
return self._subconfig.identifiers
|
else:
|
||||||
identifiers = []
|
func = self._identifiers_all_no_identifiers
|
||||||
dynconfig = None
|
return func(subconfig, uncalculated, convert)
|
||||||
while not dynconfig:
|
|
||||||
if subconfig.option.impl_is_optiondescription() and subconfig.option.impl_is_dynoptiondescription():
|
def _identifiers_all(self, subconfig, uncalculated, convert):
|
||||||
dynconfig = subconfig
|
dynconfig = None
|
||||||
subconfig = subconfig.parent
|
_subconfig = subconfig
|
||||||
for identifier in self._subconfig.identifiers:
|
while not dynconfig:
|
||||||
if identifier is None:
|
if _subconfig.option.impl_is_optiondescription() and _subconfig.option.impl_is_dynoptiondescription():
|
||||||
continue
|
dynconfig = _subconfig
|
||||||
identifiers.append(dynconfig.option.convert_identifier_to_path(identifier))
|
else:
|
||||||
return identifiers
|
_subconfig = _subconfig.parent
|
||||||
|
identifiers = []
|
||||||
|
for identifier in _subconfig.identifiers:
|
||||||
|
if convert:
|
||||||
|
identifier = dynconfig.option.convert_identifier_to_path(identifier)
|
||||||
|
identifiers.append(identifier)
|
||||||
|
return identifiers
|
||||||
|
|
||||||
|
def _identifiers_all_no_identifiers(self, subconfig, uncalculated, convert):
|
||||||
|
"""dyn{{ identifier }}.var{{ identifier }}.var
|
||||||
|
=> dyn["val1", "val2"]
|
||||||
|
=> var["val3", "val4"]
|
||||||
|
returns [["val1", "val3"], ["val1", "val4"], ["val2", "val3"], ["val2", "val4"]]
|
||||||
|
"""
|
||||||
|
identifiers = []
|
||||||
|
while True:
|
||||||
|
if subconfig.option.impl_is_optiondescription() and subconfig.option.impl_is_dynoptiondescription():
|
||||||
|
if not subconfig.is_self_dynamic_without_identifiers:
|
||||||
|
new_identifiers = [subconfig.identifiers[-1]]
|
||||||
|
else:
|
||||||
|
new_identifiers = subconfig.option.get_identifiers(subconfig.parent, uncalculated=uncalculated, convert=convert)
|
||||||
|
if isinstance(new_identifiers, Calculation):
|
||||||
|
if identifiers:
|
||||||
|
identifiers = [[new_identifiers] + old_identifiers for old_identifiers in identifiers]
|
||||||
|
else:
|
||||||
|
identifiers = [new_identifiers]
|
||||||
|
elif identifiers:
|
||||||
|
identifiers = [[identifier] + old_identifiers for identifier in new_identifiers for old_identifiers in identifiers]
|
||||||
|
else:
|
||||||
|
identifiers = [[identifier] for identifier in new_identifiers]
|
||||||
|
subconfig = subconfig.parent
|
||||||
|
if subconfig is None:
|
||||||
|
break
|
||||||
|
return identifiers
|
||||||
|
|
||||||
|
def _identifiers_only_self(self, subconfig, uncalculated, convert):
|
||||||
if (
|
if (
|
||||||
not self._subconfig.option.impl_is_optiondescription()
|
not subconfig.option.impl_is_optiondescription()
|
||||||
or not self._subconfig.option.impl_is_dynoptiondescription()
|
or not subconfig.option.impl_is_dynoptiondescription()
|
||||||
):
|
):
|
||||||
raise ConfigError(
|
raise ConfigError(
|
||||||
_(
|
_(
|
||||||
"the option {0} is not a dynamic option, cannot get identifiers with only_self parameter to True"
|
"the option {0} is not a dynamic option, cannot get identifiers with only_self parameter to True"
|
||||||
).format(self._subconfig.path),
|
).format(subconfig.path),
|
||||||
subconfig=subconfig,
|
subconfig=subconfig,
|
||||||
)
|
)
|
||||||
return self._subconfig.option.get_identifiers(
|
dynconfig = None
|
||||||
self._subconfig.parent,
|
_subconfig = subconfig
|
||||||
|
while not dynconfig:
|
||||||
|
if _subconfig.option.impl_is_optiondescription() and _subconfig.option.impl_is_dynoptiondescription():
|
||||||
|
dynconfig = _subconfig
|
||||||
|
_subconfig = _subconfig.parent
|
||||||
|
return dynconfig.option.get_identifiers(
|
||||||
|
dynconfig.parent,
|
||||||
uncalculated=uncalculated,
|
uncalculated=uncalculated,
|
||||||
convert=convert,
|
convert=convert,
|
||||||
)
|
)
|
||||||
|
|
@ -1010,7 +1053,7 @@ class TiramisuOptionValue(CommonTiramisuOption, _TiramisuODGet):
|
||||||
|
|
||||||
_validate_properties = True
|
_validate_properties = True
|
||||||
|
|
||||||
@option_type(["option", "symlink", "with_index", "optiondescription"])
|
@option_type(["option", "symlink", "with_index", "optiondescription", "dynoption_or_uncalculated"])
|
||||||
def get(
|
def get(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
|
|
@ -1074,7 +1117,7 @@ class TiramisuOptionValue(CommonTiramisuOption, _TiramisuODGet):
|
||||||
values.reset(self._subconfig)
|
values.reset(self._subconfig)
|
||||||
|
|
||||||
@option_type(
|
@option_type(
|
||||||
["option", "with_or_without_index", "symlink", "dont_validate_property"]
|
["option", "with_or_without_index", "symlink", "dont_validate_property", "dynoption_or_uncalculated"]
|
||||||
)
|
)
|
||||||
def default(
|
def default(
|
||||||
self,
|
self,
|
||||||
|
|
@ -1113,7 +1156,7 @@ class TiramisuOptionValue(CommonTiramisuOption, _TiramisuODGet):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@option_type(["choice", "with_index", "allow_dynoption"])
|
@option_type(["choice", "with_index_or_uncalculated", "allow_dynoption"])
|
||||||
def list(
|
def list(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
|
|
@ -1127,7 +1170,7 @@ class TiramisuOptionValue(CommonTiramisuOption, _TiramisuODGet):
|
||||||
uncalculated,
|
uncalculated,
|
||||||
)
|
)
|
||||||
|
|
||||||
@option_type("leader")
|
@option_type(["leader"])
|
||||||
def pop(
|
def pop(
|
||||||
self,
|
self,
|
||||||
index: int,
|
index: int,
|
||||||
|
|
@ -1350,7 +1393,7 @@ class TiramisuOption(
|
||||||
remotable=remotable,
|
remotable=remotable,
|
||||||
)
|
)
|
||||||
|
|
||||||
@option_type("optiondescription")
|
@option_type(["optiondescription"])
|
||||||
def dict(
|
def dict(
|
||||||
self,
|
self,
|
||||||
clearable: str = "all",
|
clearable: str = "all",
|
||||||
|
|
@ -1363,7 +1406,7 @@ class TiramisuOption(
|
||||||
self._load_dict(clearable, remotable)
|
self._load_dict(clearable, remotable)
|
||||||
return self._tiramisu_dict.todict(form)
|
return self._tiramisu_dict.todict(form)
|
||||||
|
|
||||||
@option_type("optiondescription")
|
@option_type(["optiondescription"])
|
||||||
def updates(
|
def updates(
|
||||||
self,
|
self,
|
||||||
body: List,
|
body: List,
|
||||||
|
|
@ -1445,17 +1488,20 @@ class TiramisuContextValue(TiramisuConfig, _TiramisuODGet):
|
||||||
only_mandatory=True,
|
only_mandatory=True,
|
||||||
):
|
):
|
||||||
if id(subconfig.config_bag) != id(config_bag):
|
if id(subconfig.config_bag) != id(config_bag):
|
||||||
|
old_is_dynamic_without_identifiers = subconfig.is_self_dynamic_without_identifiers
|
||||||
subconfig = subconfig.__class__(option=subconfig.option,
|
subconfig = subconfig.__class__(option=subconfig.option,
|
||||||
index=subconfig.index,
|
index=subconfig.index,
|
||||||
path=subconfig.path,
|
path=subconfig.path,
|
||||||
config_bag=config_bag,
|
config_bag=config_bag,
|
||||||
parent=subconfig.parent,
|
parent=subconfig.parent,
|
||||||
identifiers=subconfig.identifiers,
|
identifiers=subconfig.identifiers,
|
||||||
|
identifier=None,
|
||||||
true_path=subconfig.true_path,
|
true_path=subconfig.true_path,
|
||||||
properties=subconfig.properties,
|
properties=subconfig.properties,
|
||||||
validate_properties=False,
|
validate_properties=False,
|
||||||
check_dynamic_without_identifiers=False,
|
check_dynamic_without_identifiers=False,
|
||||||
)
|
)
|
||||||
|
subconfig.is_self_dynamic_without_identifiers = old_is_dynamic_without_identifiers
|
||||||
else:
|
else:
|
||||||
subconfig._length = None
|
subconfig._length = None
|
||||||
options.append(
|
options.append(
|
||||||
|
|
|
||||||
|
|
@ -691,6 +691,7 @@ def manager_callback(
|
||||||
subconfigs_is_a_list = False
|
subconfigs_is_a_list = False
|
||||||
for name in paths:
|
for name in paths:
|
||||||
new_parents = []
|
new_parents = []
|
||||||
|
identifier = undefined
|
||||||
for parent in parents:
|
for parent in parents:
|
||||||
doption = parent.option.get_child(
|
doption = parent.option.get_child(
|
||||||
name,
|
name,
|
||||||
|
|
@ -699,11 +700,12 @@ def manager_callback(
|
||||||
allow_dynoption=True,
|
allow_dynoption=True,
|
||||||
)
|
)
|
||||||
if doption.impl_is_dynoptiondescription():
|
if doption.impl_is_dynoptiondescription():
|
||||||
if not identifiers:
|
if identifier is undefined:
|
||||||
identifier = None
|
if not identifiers:
|
||||||
else:
|
identifier = None
|
||||||
identifier = identifiers.pop(0)
|
else:
|
||||||
if not identifier:
|
identifier = identifiers.pop(0)
|
||||||
|
if identifier is None:
|
||||||
subconfigs_is_a_list = True
|
subconfigs_is_a_list = True
|
||||||
new_parents.extend(
|
new_parents.extend(
|
||||||
parent.dyn_to_subconfig(
|
parent.dyn_to_subconfig(
|
||||||
|
|
@ -879,17 +881,20 @@ def carry_out_calculation(
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
config_bag = config_bag.copy()
|
config_bag = config_bag.copy()
|
||||||
config_bag.set_permissive()
|
config_bag.set_permissive()
|
||||||
|
old_is_dynamic_without_identifiers = subconfig.is_dynamic_without_identifiers
|
||||||
subconfig = subconfig.__class__(option=subconfig.option,
|
subconfig = subconfig.__class__(option=subconfig.option,
|
||||||
index=subconfig.index,
|
index=subconfig.index,
|
||||||
path=subconfig.path,
|
path=subconfig.path,
|
||||||
config_bag=config_bag,
|
config_bag=config_bag,
|
||||||
parent=subconfig.parent,
|
parent=subconfig.parent,
|
||||||
identifiers=subconfig.identifiers,
|
identifiers=subconfig.identifiers,
|
||||||
|
identifier=None,
|
||||||
true_path=subconfig.true_path,
|
true_path=subconfig.true_path,
|
||||||
properties=subconfig.properties,
|
properties=subconfig.properties,
|
||||||
validate_properties=False,
|
validate_properties=False,
|
||||||
check_dynamic_without_identifiers=False,
|
check_dynamic_without_identifiers=False,
|
||||||
)
|
)
|
||||||
|
subconfig.is_dynamic_without_identifiers = old_is_dynamic_without_identifiers
|
||||||
if callback_params:
|
if callback_params:
|
||||||
for key, param in chain(
|
for key, param in chain(
|
||||||
fake_items(callback_params.args), callback_params.kwargs.items()
|
fake_items(callback_params.args), callback_params.kwargs.items()
|
||||||
|
|
|
||||||
|
|
@ -275,6 +275,7 @@ class SubConfig:
|
||||||
"transitive_properties",
|
"transitive_properties",
|
||||||
"is_dynamic",
|
"is_dynamic",
|
||||||
"is_dynamic_without_identifiers",
|
"is_dynamic_without_identifiers",
|
||||||
|
"is_self_dynamic_without_identifiers",
|
||||||
"identifiers",
|
"identifiers",
|
||||||
"_length",
|
"_length",
|
||||||
)
|
)
|
||||||
|
|
@ -287,6 +288,7 @@ class SubConfig:
|
||||||
config_bag: ConfigBag,
|
config_bag: ConfigBag,
|
||||||
parent: Optional["SubConfig"],
|
parent: Optional["SubConfig"],
|
||||||
identifiers: Optional[list[str]],
|
identifiers: Optional[list[str]],
|
||||||
|
identifier: Optional[str],
|
||||||
*,
|
*,
|
||||||
true_path: Optional[str] = None,
|
true_path: Optional[str] = None,
|
||||||
# for python 3.9 properties: Union[list[str], undefined] = undefined,
|
# for python 3.9 properties: Union[list[str], undefined] = undefined,
|
||||||
|
|
@ -308,6 +310,7 @@ class SubConfig:
|
||||||
)
|
)
|
||||||
self.apply_requires = not is_follower or index is not None
|
self.apply_requires = not is_follower or index is not None
|
||||||
self.true_path = true_path
|
self.true_path = true_path
|
||||||
|
self.is_self_dynamic_without_identifiers = identifier is None
|
||||||
if self.option.impl_is_dynoptiondescription():
|
if self.option.impl_is_dynoptiondescription():
|
||||||
self.is_dynamic = True
|
self.is_dynamic = True
|
||||||
self.is_dynamic_without_identifiers = identifiers is None or (
|
self.is_dynamic_without_identifiers = identifiers is None or (
|
||||||
|
|
@ -321,7 +324,8 @@ class SubConfig:
|
||||||
and self.is_dynamic_without_identifiers
|
and self.is_dynamic_without_identifiers
|
||||||
!= parent.is_dynamic_without_identifiers
|
!= parent.is_dynamic_without_identifiers
|
||||||
):
|
):
|
||||||
raise AttributeOptionError(true_path, "option-dynamic")
|
self.is_dynamic_without_identifiers = True
|
||||||
|
# raise AttributeOptionError(true_path, "option-dynamic")
|
||||||
elif parent:
|
elif parent:
|
||||||
self.is_dynamic = parent.is_dynamic
|
self.is_dynamic = parent.is_dynamic
|
||||||
self.is_dynamic_without_identifiers = parent.is_dynamic_without_identifiers
|
self.is_dynamic_without_identifiers = parent.is_dynamic_without_identifiers
|
||||||
|
|
@ -339,15 +343,14 @@ class SubConfig:
|
||||||
self.config_bag.context.get_settings().validate_properties(self)
|
self.config_bag.context.get_settings().validate_properties(self)
|
||||||
self._properties = undefined
|
self._properties = undefined
|
||||||
self.config_bag.context.get_settings().validate_properties(self)
|
self.config_bag.context.get_settings().validate_properties(self)
|
||||||
if self.apply_requires and self.option.impl_is_optiondescription():
|
if validate_properties and self.apply_requires and self.option.impl_is_optiondescription() and self.path and self.properties is not None:
|
||||||
if self.path and self.properties is not None:
|
settings = config_bag.context.get_settings()
|
||||||
settings = config_bag.context.get_settings()
|
self.transitive_properties = settings.calc_transitive_properties(
|
||||||
self.transitive_properties = settings.calc_transitive_properties(
|
self,
|
||||||
self,
|
self.properties,
|
||||||
self.properties,
|
)
|
||||||
)
|
else:
|
||||||
else:
|
self.transitive_properties = frozenset()
|
||||||
self.transitive_properties = frozenset()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def properties(self):
|
def properties(self):
|
||||||
|
|
@ -515,6 +518,7 @@ class SubConfig:
|
||||||
config_bag,
|
config_bag,
|
||||||
self,
|
self,
|
||||||
identifiers,
|
identifiers,
|
||||||
|
identifier,
|
||||||
properties=properties,
|
properties=properties,
|
||||||
validate_properties=validate_properties,
|
validate_properties=validate_properties,
|
||||||
true_path=true_path,
|
true_path=true_path,
|
||||||
|
|
@ -560,8 +564,10 @@ class SubConfig:
|
||||||
cconfig_bag,
|
cconfig_bag,
|
||||||
self,
|
self,
|
||||||
self.identifiers,
|
self.identifiers,
|
||||||
|
None,
|
||||||
validate_properties=False,
|
validate_properties=False,
|
||||||
)
|
)
|
||||||
|
subconfig.is_self_dynamic_without_identifiers = self.is_self_dynamic_without_identifiers
|
||||||
#FIXME
|
#FIXME
|
||||||
#self._length = len(cconfig_bag.context.get_value(subconfig))
|
#self._length = len(cconfig_bag.context.get_value(subconfig))
|
||||||
length = len(cconfig_bag.context.get_value(subconfig))
|
length = len(cconfig_bag.context.get_value(subconfig))
|
||||||
|
|
@ -664,16 +670,19 @@ class SubConfig:
|
||||||
def change_context(self, context) -> "SubConfig":
|
def change_context(self, context) -> "SubConfig":
|
||||||
config_bag = self.config_bag.copy()
|
config_bag = self.config_bag.copy()
|
||||||
config_bag.context = context
|
config_bag.context = context
|
||||||
return SubConfig(
|
subconfig = SubConfig(
|
||||||
self.option,
|
self.option,
|
||||||
self.index,
|
self.index,
|
||||||
self.path,
|
self.path,
|
||||||
config_bag,
|
config_bag,
|
||||||
self.parent,
|
self.parent,
|
||||||
self.identifiers,
|
self.identifiers,
|
||||||
|
None,
|
||||||
true_path=self.true_path,
|
true_path=self.true_path,
|
||||||
validate_properties=False,
|
validate_properties=False,
|
||||||
)
|
)
|
||||||
|
subconfig.is_self_dynamic_without_identifiers = self.is_self_dynamic_without_identifiers
|
||||||
|
return subconfig
|
||||||
|
|
||||||
|
|
||||||
class _Config(CCache):
|
class _Config(CCache):
|
||||||
|
|
@ -761,6 +770,7 @@ class _Config(CCache):
|
||||||
config_bag,
|
config_bag,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_sub_config(
|
def get_sub_config(
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,13 @@ class Option(BaseOption):
|
||||||
default = getattr(self, "_default", undefined)
|
default = getattr(self, "_default", undefined)
|
||||||
if default is undefined:
|
if default is undefined:
|
||||||
if is_multi:
|
if is_multi:
|
||||||
default = []
|
if self.impl_is_follower():
|
||||||
|
if submulti:
|
||||||
|
default = getattr(self, "_default_multi", [])
|
||||||
|
else:
|
||||||
|
default = getattr(self, "_default_multi", None)
|
||||||
|
else:
|
||||||
|
default = []
|
||||||
else:
|
else:
|
||||||
default = None
|
default = None
|
||||||
elif is_multi and isinstance(default, tuple):
|
elif is_multi and isinstance(default, tuple):
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue