feat: property.get(uncalculated=True) is now possible for an dynoptiondescription without identifiers
This commit is contained in:
parent
e8921795d3
commit
e0f16b14c7
5 changed files with 69 additions and 14 deletions
|
|
@ -13,7 +13,7 @@ from tiramisu import BoolOption, StrOption, ChoiceOption, IPOption, \
|
|||
Config, \
|
||||
Params, ParamOption, ParamValue, ParamIdentifier, ParamSelfOption, ParamDynOption, ParamIndex, ParamSelfInformation, ParamInformation, \
|
||||
Calculation, calc_value
|
||||
from tiramisu.error import PropertiesOptionError, ConfigError, ConflictError, ValueOptionError
|
||||
from tiramisu.error import PropertiesOptionError, ConfigError, ConflictError, ValueOptionError, AttributeOptionError
|
||||
|
||||
|
||||
def display_name(kls, subconfig, with_quote=False) -> str:
|
||||
|
|
@ -317,6 +317,20 @@ def test_prop_dyndescription():
|
|||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_prop_dyndescription_uncalculated():
|
||||
st = StrOption('st', '', properties=('test',))
|
||||
od = OptionDescription('od', '', [st], properties=('test_od',))
|
||||
dod = DynOptionDescription('dod', '', [od], identifiers=Calculation(return_list))
|
||||
od2 = OptionDescription('od', '', [dod])
|
||||
cfg = Config(od2)
|
||||
assert set(cfg.option('dod.od').property.get(uncalculated=True)) == {'test_od'}
|
||||
assert set(cfg.option('dod.od.st').property.get(uncalculated=True)) == {'test', 'validator'}
|
||||
with pytest.raises(AttributeOptionError):
|
||||
set(cfg.option('dod.od').property.get())
|
||||
with pytest.raises(AttributeOptionError):
|
||||
set(cfg.option('dod.od.st').property.get())
|
||||
|
||||
|
||||
def test_prop_dyndescription_force_store_value():
|
||||
st = StrOption('st', '', properties=('force_store_value',))
|
||||
dod = DynOptionDescription('dod', '', [st], identifiers=Calculation(return_list))
|
||||
|
|
@ -451,6 +465,30 @@ def test_callback_dyndescription_outside_optional():
|
|||
# assert not list_sessions()
|
||||
|
||||
|
||||
def test_dyndescription_subdyn():
|
||||
lst = StrOption('lst', '', ['val1', 'val2'], multi=True)
|
||||
st = StrOption('st', '', 'val1')
|
||||
dod = DynOptionDescription('dod', '', [st], identifiers=Calculation(return_list))
|
||||
out = StrOption('out', '', Calculation(return_dynval, Params(ParamDynOption(st, ['val1', None]))), multi=True, properties=('notunique',))
|
||||
dod2 = DynOptionDescription('dod2', '', [dod, out], identifiers=Calculation(return_list))
|
||||
od = OptionDescription('od', '', [dod2])
|
||||
od2 = OptionDescription('od', '', [od, lst])
|
||||
cfg = Config(od2)
|
||||
cfg.property.read_write()
|
||||
assert cfg.option('od.dod2val1.dodval1.st').value.get() == 'val1'
|
||||
with pytest.raises(AttributeOptionError):
|
||||
cfg.option('od.dod2.dodval1.st').value.get()
|
||||
with pytest.raises(AttributeOptionError):
|
||||
cfg.option('od.dod2val1.dod.st').value.get()
|
||||
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.dod2.dod.st').property.get(uncalculated=True)) == {'validator'}
|
||||
with pytest.raises(AttributeOptionError):
|
||||
cfg.option('od.dod2.dodval1.st').property.get(uncalculated=True)
|
||||
with pytest.raises(AttributeOptionError):
|
||||
cfg.option('od.dod2val1.dod.st').property.get(uncalculated=True)
|
||||
|
||||
|
||||
def test_callback_dyndescription_subdyn():
|
||||
lst = StrOption('lst', '', ['val1', 'val2'], multi=True)
|
||||
st = StrOption('st', '', 'val1')
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ from .error import (
|
|||
LeadershipError,
|
||||
ValueErrorWarning,
|
||||
PropertiesOptionError,
|
||||
AttributeOptionError,
|
||||
)
|
||||
from .i18n import _
|
||||
from .setting import (
|
||||
|
|
@ -123,7 +124,6 @@ class TiramisuHelp:
|
|||
|
||||
class CommonTiramisu(TiramisuHelp):
|
||||
_validate_properties = True
|
||||
_allow_dynoption = False
|
||||
|
||||
def _set_subconfig(self) -> None:
|
||||
if not self._subconfig:
|
||||
|
|
@ -133,7 +133,7 @@ class CommonTiramisu(TiramisuHelp):
|
|||
self._path,
|
||||
self._index,
|
||||
validate_properties=False,
|
||||
allow_dynoption=self._allow_dynoption,
|
||||
allow_dynoption=True,
|
||||
)
|
||||
except AssertionError as err:
|
||||
raise ConfigError(str(err))
|
||||
|
|
@ -149,8 +149,6 @@ def option_type(typ):
|
|||
@wraps(func)
|
||||
def wrapped(*args, **kwargs):
|
||||
self = args[0]
|
||||
if isinstance(typ, list) and "allow_dynoption" in typ:
|
||||
self._allow_dynoption = True
|
||||
config_bag = self._config_bag
|
||||
if self._config_bag.context.impl_type == "group" and "group" in types:
|
||||
options_bag = [
|
||||
|
|
@ -164,6 +162,9 @@ def option_type(typ):
|
|||
kwargs["is_group"] = True
|
||||
return func(self, options_bag, *args[1:], **kwargs)
|
||||
self._set_subconfig()
|
||||
if (not isinstance(typ, list) or "allow_dynoption" not in typ) and self._subconfig.is_dynamic_without_identifiers:
|
||||
raise AttributeOptionError(self._subconfig.path, "option-dynamic")
|
||||
|
||||
option = self._subconfig.option
|
||||
error_type = None
|
||||
if "dynamic" in types:
|
||||
|
|
@ -668,7 +669,7 @@ class TiramisuOptionProperty(CommonTiramisuOption):
|
|||
|
||||
_validate_properties = False
|
||||
|
||||
@option_type(["option", "optiondescription", "with_index", "symlink"])
|
||||
@option_type(["option", "optiondescription", "with_index", "symlink", "allow_dynoption"])
|
||||
def get(
|
||||
self,
|
||||
*,
|
||||
|
|
@ -677,6 +678,8 @@ class TiramisuOptionProperty(CommonTiramisuOption):
|
|||
uncalculated: bool = False,
|
||||
):
|
||||
"""Get properties for an option"""
|
||||
if self._subconfig.is_dynamic_without_identifiers and not uncalculated:
|
||||
raise AttributeOptionError(self._subconfig.path, "option-dynamic")
|
||||
settings = self._config_bag.context.get_settings()
|
||||
if not only_raises:
|
||||
return settings.getproperties(
|
||||
|
|
@ -797,9 +800,8 @@ class TiramisuOptionInformation(CommonTiramisuOption):
|
|||
"""Manage option's informations"""
|
||||
|
||||
_validate_properties = False
|
||||
_allow_dynoption = True
|
||||
|
||||
@option_type(["option", "optiondescription", "with_or_without_index", "symlink"])
|
||||
@option_type(["option", "optiondescription", "with_or_without_index", "symlink", "allow_dynoption"])
|
||||
def get(
|
||||
self,
|
||||
name: str,
|
||||
|
|
@ -812,7 +814,7 @@ class TiramisuOptionInformation(CommonTiramisuOption):
|
|||
default,
|
||||
)
|
||||
|
||||
@option_type(["option", "optiondescription"])
|
||||
@option_type(["option", "optiondescription", "allow_dynoption"])
|
||||
def set(self, key: str, value: Any) -> None:
|
||||
"""Set information"""
|
||||
self._config_bag.context.get_values().set_information(
|
||||
|
|
@ -821,7 +823,7 @@ class TiramisuOptionInformation(CommonTiramisuOption):
|
|||
value,
|
||||
)
|
||||
|
||||
@option_type(["option", "optiondescription"])
|
||||
@option_type(["option", "optiondescription", "allow_dynoption"])
|
||||
def remove(
|
||||
self,
|
||||
key: str,
|
||||
|
|
@ -832,7 +834,7 @@ class TiramisuOptionInformation(CommonTiramisuOption):
|
|||
path=self._path,
|
||||
)
|
||||
|
||||
@option_type(["option", "optiondescription", "with_or_without_index", "symlink"])
|
||||
@option_type(["option", "optiondescription", "with_or_without_index", "symlink", "allow_dynoption"])
|
||||
def list(self) -> list:
|
||||
"""List information's keys"""
|
||||
lst1 = set(self._subconfig.option._list_information())
|
||||
|
|
@ -1106,7 +1108,6 @@ class TiramisuOption(
|
|||
self._path = path
|
||||
self._index = index
|
||||
self._config_bag = config_bag
|
||||
self._allow_dynoption = allow_dynoption
|
||||
self._subconfig = subconfig
|
||||
if not self._registers:
|
||||
_registers(self._registers, "TiramisuOption")
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ from copy import copy, deepcopy
|
|||
from typing import Optional, List, Any, Union
|
||||
from os.path import commonprefix
|
||||
|
||||
from .error import PropertiesOptionError, ConfigError, ConflictError, LeadershipError
|
||||
from .error import PropertiesOptionError, ConfigError, ConflictError, LeadershipError, AttributeOptionError
|
||||
from .option import DynOptionDescription, Leadership, Option
|
||||
from .setting import ConfigBag, Settings, undefined, groups
|
||||
from .value import Values, owners
|
||||
|
|
@ -237,6 +237,7 @@ class SubConfig:
|
|||
"apply_requires",
|
||||
"transitive_properties",
|
||||
"is_dynamic",
|
||||
"is_dynamic_without_identifiers",
|
||||
"identifiers",
|
||||
"_length",
|
||||
)
|
||||
|
|
@ -254,6 +255,7 @@ class SubConfig:
|
|||
# for python 3.9 properties: Union[list[str], undefined] = undefined,
|
||||
properties=undefined,
|
||||
validate_properties: bool = True,
|
||||
check_dynamic_without_identifiers: bool = True,
|
||||
) -> None:
|
||||
self.index = index
|
||||
self.identifiers = identifiers
|
||||
|
|
@ -269,10 +271,17 @@ class SubConfig:
|
|||
)
|
||||
self.apply_requires = not is_follower or index is not None
|
||||
self.true_path = true_path
|
||||
if parent and parent.is_dynamic or self.option.impl_is_dynoptiondescription():
|
||||
if self.option.impl_is_dynoptiondescription():
|
||||
self.is_dynamic = True
|
||||
self.is_dynamic_without_identifiers = identifiers is None or (parent and identifiers == parent.identifiers)
|
||||
if check_dynamic_without_identifiers and parent and parent.is_dynamic and self.is_dynamic_without_identifiers != parent.is_dynamic_without_identifiers:
|
||||
raise AttributeOptionError(true_path, "option-dynamic")
|
||||
elif parent:
|
||||
self.is_dynamic = parent.is_dynamic
|
||||
self.is_dynamic_without_identifiers = parent.is_dynamic_without_identifiers
|
||||
else:
|
||||
self.is_dynamic = False
|
||||
self.is_dynamic_without_identifiers = False
|
||||
self._properties = properties
|
||||
if validate_properties:
|
||||
if self.path and self._properties is undefined:
|
||||
|
|
@ -433,6 +442,7 @@ class SubConfig:
|
|||
check_index: bool = True,
|
||||
config_bag: ConfigBag = None,
|
||||
true_path: Optional[str] = None,
|
||||
check_dynamic_without_identifiers: bool = True,
|
||||
) -> "SubConfig":
|
||||
# pylint: disable=too-many-branches,too-many-locals,too-many-arguments
|
||||
if config_bag is None:
|
||||
|
|
@ -461,6 +471,7 @@ class SubConfig:
|
|||
properties=properties,
|
||||
validate_properties=validate_properties,
|
||||
true_path=true_path,
|
||||
check_dynamic_without_identifiers=check_dynamic_without_identifiers,
|
||||
)
|
||||
if check_index and index is not None:
|
||||
if option.impl_is_optiondescription() or not option.impl_is_follower():
|
||||
|
|
@ -512,6 +523,7 @@ class SubConfig:
|
|||
search_option: "BaseOption",
|
||||
true_path: Optional[str] = None,
|
||||
validate_properties: bool = True,
|
||||
check_dynamic_without_identifiers: bool = True,
|
||||
):
|
||||
current_option_path = self.option.impl_getpath()
|
||||
search_option_path = search_option.impl_getpath()
|
||||
|
|
@ -571,6 +583,7 @@ class SubConfig:
|
|||
None,
|
||||
validate_properties,
|
||||
true_path=true_path,
|
||||
check_dynamic_without_identifiers=check_dynamic_without_identifiers,
|
||||
)
|
||||
)
|
||||
parents = new_parents
|
||||
|
|
@ -581,6 +594,7 @@ class SubConfig:
|
|||
search_option,
|
||||
index,
|
||||
validate_properties,
|
||||
check_dynamic_without_identifiers=check_dynamic_without_identifiers,
|
||||
)
|
||||
)
|
||||
if subconfigs_is_a_list:
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ class DynOptionDescription(OptionDescription):
|
|||
None,
|
||||
False,
|
||||
properties=None,
|
||||
check_dynamic_without_identifiers=False,
|
||||
)
|
||||
identifiers = self._identifiers
|
||||
if isinstance(identifiers, list):
|
||||
|
|
|
|||
|
|
@ -395,6 +395,7 @@ class Values:
|
|||
woption(),
|
||||
true_path=subconfig.path,
|
||||
validate_properties=False,
|
||||
check_dynamic_without_identifiers=False,
|
||||
)
|
||||
if not isinstance(options, list):
|
||||
options = [options]
|
||||
|
|
|
|||
Loading…
Reference in a new issue